Функторы предиката упаковки - PullRequest
2 голосов
/ 13 октября 2011

Меня интересуют соглашения и лучшие практики, касающиеся упаковки функторов предикатов. Например, учитывая класс как:

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 ]

1 голос
/ 13 октября 2011

Это открыто для обсуждения.Я предпочитаю создавать вложенный класс.Таким образом, функтор, предназначенный только для работы с конкретным типом объекта, в этом объекте ограничивается пространством имен.

Я также обычно называю предикат 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") );

Я предпочитаю этот метод, потому что семантика Timer::match_name("Flibbidy") чрезвычайно ясна, когдаглядя на этот код 6 месяцев спустя.

Я также осторожно извлекаю свой функтор из std::unary_function (хотя мой приведенный выше вывод может иметь обратные параметры).

1 голос
/ 13 октября 2011

Мне лично, в его собственных заголовочных и cpp файлах.Используя #include "Timer.h" в заголовочном файле TimerNameIs:

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

При этом вы изолируете Timer и TimerNameI от одного к другому.

...