2011-10-12 44 views
2

我想知道關於謂詞函子包裝的約定和最佳實踐。例如,給定的一類,如:包裝謂詞函子

class Timer 
{ 
public: 
    Timer(const std::string& name, int interval); 
    bool nameIs(const std::string& name) const; 
private: 
    std::string name_; 
    int interval_; 
}; 

TimerVec類使用的是(在一種情況下):

class TimerVec 
{ 
public: 
    typedef std::vector<Timer>::iterator iterator;`` 
    <... ctors, etc ...> 
    iterator findByName(const std::string& name); 
private: 
    std::vector<Timer> timers_; 
}; 

並具有謂詞函子像:

class TimerNameIs 
{ 
public: 
    TimerNameIs(const std::string& name) : name_(name) {} 
    bool operator()(const Timer& t) { return t.nameIs(name_); } 
private: 
    const std::string& name_; 
}; 

我可以想想一些地方可以放上函子代碼,有些是:

  1. 緊接在定時器聲明之後的頭文件中
  2. 嵌套在定時器內(即,所以裁判成爲Timer::TimerNameIs
  3. 內TimerVec(目前唯一的用戶)
  4. 嵌套在提前爲TimerVec::findByName實施(再次僅它使用的地方)的匿名命名空間

雖然任何這些會我相當喜歡#2,但這不是我見過的。有沒有具體的理由支持特定的選擇?

+2

如果它只被一個函數使用,我會暫時使用#4。事實上,你可能根本不需要函子(C++ 11 lambda等)。如果您稍後發現其他用途,則重構應該很簡單。 - 如果我選擇重構,我絕對不會使用#3或任何其他強制無關代碼重新編譯的選項。 – UncleBens

+0

@UncleBens在這種情況下,lambda顯然是最好的解決方案。但+1,因爲我應該想到它,但沒有。 – rlduffy

回答

1

這是開放辯論。我更喜歡創建一個嵌套類。通過這種方式,僅用於處理特定類型對象的仿函數是該對象內的命名空間範圍。

我也通常命名謂詞match_xxx其中xxx是我匹配的參數。

機智:

class Timer 
{ 
    // ... 
public: 
    class match_name : public std::unary_function<Timer, bool> 
    { 
    public: 
    match_name(const std::string& name) : name_(name) {} 
    bool operator()(const Timer& t) { return t.nameIs(name_); } 
    private: 
    const std::string& name_; 
    }; 
}; 

...這正是如此使用:

std::find_if(v.begin(), v.end(), Timer::match_name("Flibbidy")); 

在這個代號爲6個月後看的時候我喜歡這種方法,因爲Timer::match_name("Flibbidy")語義是非常清楚的。

我也很小心從std::unary_function派生我的仿函數(雖然我上面的派生可能有參數顛倒)。

+0

我知道任何答案都是有爭議的,但你的推理是合理的。並且從unary_function派生出的建議是點亮的。所有這一切,你證實了我的偏見:) – rlduffy

1

我個人在它自己的頭文件和cpp文件中。在TimerNameIs頭文件使用#include "Timer.h"

#include "Timer.h" 
#include <string> 

class TimerNameIs 
{ 
    public: 
     TimerNameIs(const std::string& name) : name_(name) {} 
     bool operator()(const Timer& t) { return t.nameIs(name_); } 
    private: 
     const std::string& name_; 
}; 

這樣做,你從一個到另一個隔離定時器和TimerNameIs。

+0

+1因爲我也應該考慮這一點,但沒有。該項目的風格是相關類被分組爲源文件。另外,我不是Java風格的每類源文件模型的忠實粉絲。事情的實質是Timer和TimerNameI是無情的耦合,所以爲什麼不讓源代碼組確認? – rlduffy

+0

@rlduffy所以,使用第二個選項。這樣'TimeVec'可以毫無問題地使用它。考慮未來的發展和用途,不要使用第三種選擇。 –