开发者

Packaging Predicate Functors

I'm wondering about conventions and best practices regarding the packaging of predicate functors. For example, given a class like:

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

that is (in one case) used in class TimerVec:

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

and has a predicate functor like:

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

I can think of a number of places to put the functor code, some being:

  1. In the header file immediately following the declaration of Timer
  2. Nested inside Timer (i.e. so the ref becomes Timer::TimerNameIs)
  3. Nested inside TimerVec (currently the only user)
  4. In an anonymous namespace ahead of the implementation for TimerVec::findByName (again the only place it's used)

While any of these would be adequate I'm rather drawn to #2, but it's not something I've ever seen done. Are there any concrete reasons favoring a particular option?


This is open to debate. I prefer to create a nested class. This way a functor that is intended only to work with a particular type of object is namespace-scoped within that object.

I also generally name the predicate match_xxx where xxx is the parameter I'm matching on.

To wit:

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_;
  };
};

...which is utilized thusly:

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

I prefer this method because the semantics of Timer::match_name("Flibbidy") are exceedingly clear when looking at this code 6 months later.

I also am careful to derive my functor from std::unary_function (although my derivation above might have the parameters reversed).


Me, personally, in it's own header and cpp files. Using #include "Timer.h" in the TimerNameIsheader file:

#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_;
};

Doing this, you isolate Timer and TimerNameIs from one to the other.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜