В чем разница между предикатом и функтором?

Я читать кто-то вызывает класс с конструктором и operator() a :

// Example
class Foo {
  public:
    Foo(Bar);
    bool operator()(Baz);
  private:
    Bar bar;
};

однако я не слышал этого слова используется в этом контексте раньше. Я бы назвал это функтор. Для меня будет что-то из области формальной логики.

это вызывает следующие вопросы:

  • это обычная слово для чего-то вроде Foo?
  • оба термина используются взаимозаменяемо, или они означают несколько разные вещи?
  • или
    • тип возврата (bool против чего-то еще) имеют к этому какое-то отношение?
    • насчет operator() будучи const?

5 ответов


функтор - это термин, который относится к сущности, поддерживающей operator () в выражениях (с нулевыми или более параметрами), т. е. что-то, что синтаксически ведет себя как функция. Функтор не обязательно является объектом некоторого класса с перегруженным operator (). Обычные имена функций также являются функторами. Хотя в некоторых контекстах вы можете видеть термин "функтор", используемый в более узком и эксклюзивном смысле: просто объекты класса, но не обычные функции.

A это специфический вид функтора: функтор, который вычисляет логическое значение. Это не обязательно значение bool тип, а значение типа "булево" семантика. Тип должен быть неявно преобразуемым в bool хотя.


показанный класс является функтором, реализующим предикат.

A является булевой функцией.

о operator() неconst здесь: в идеале должно быть const да.


предикат-это особый вид объекта функции. Смотрите это отлично колонки Николай Джосутису. Цитата:

объект функции, возвращающий логическое значение, является предикатом. вот что почти все учебники, книги и руководства пишут о предикатах из STL. Однако это еще не все.

однако, есть дополнительное требование, которое, к сожалению, не упомянутый в любом руководстве или в Стандарт C++: предикат должен всегда возвращайте один и тот же результат для одного и того же значения.

или, на языке C++:вы должны объявить operator () как постоянная функция-член (и не играйте в игры с изменяемыми или слепками). По той же причине копия предиката должна иметь то же состояние как оригинал.

причина в том, что алгоритмы STL будут копировать функциональные объекты вокруг, и копирование не должно влиять результат применения объектов функции.

template<typename Arg0>
struct UnaryPredicate
:
    public std::function<bool(Arg0 const&)>
{
    bool operator()(Arg0 const& a0) const
    {
        return // your code here
    }
};

template<typename Arg0, typename Arg1>
struct BinaryPredicate
:
    public std::function<bool(Arg0 const&, Arg1 const&)>
{
    bool operator()(Arg const& a0, Arg const& a1) const
    {
        return // your code here
    }
};

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

struct is_odd
{
    is_odd() : count(0);
    bool operartor () (int i) const { ++count; return (i % 2) == 1; }

private
    int count;
}

и...

bool isOdd(int i) { return (i % 2) == 1; }

Итак, что такого особенного в функторе? Он поддерживает состояние, если вы хотите! Это означает, что, хотя эти две строки кода делают то же самое (предположим, что v - вектор со значениями 0-9)...

for_each(v.begin(), v.end(), isOdd); //using C-style function pointer

и...

is_odd fn = for_each(v.begin(), v.end(), is_odd); //using functor

только с второй вариант использования вы можете затем позвонить...

int calls = fn.count;

это потому, что for_each (а также другие функции алгоритма STL) возвращает функтор, который он использовал в конце, поэтому теперь можно запросить конечное состояние.

еще одна интересная вещь, чтобы отметить, что во втором случае мы используем то, что называется "анонимным" объектом.


из MSDN:

представляет метод, который определяет набор критериев, и определяет соответствует ли указанный объект этим критериям.

http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx