В чем разница между предикатом и функтором?
Я читать кто-то вызывает класс с конструктором и operator()
a :
// Example
class Foo {
public:
Foo(Bar);
bool operator()(Baz);
private:
Bar bar;
};
однако я не слышал этого слова используется в этом контексте раньше. Я бы назвал это функтор. Для меня будет что-то из области формальной логики.
это вызывает следующие вопросы:
- это обычная слово для чего-то вроде
Foo
? - оба термина используются взаимозаменяемо, или они означают несколько разные вещи?
- или
- тип возврата (
bool
против чего-то еще) имеют к этому какое-то отношение? - насчет
operator()
будучиconst
?
- тип возврата (
5 ответов
функтор - это термин, который относится к сущности, поддерживающей operator ()
в выражениях (с нулевыми или более параметрами), т. е. что-то, что синтаксически ведет себя как функция. Функтор не обязательно является объектом некоторого класса с перегруженным operator ()
. Обычные имена функций также являются функторами. Хотя в некоторых контекстах вы можете видеть термин "функтор", используемый в более узком и эксклюзивном смысле: просто объекты класса, но не обычные функции.
A это специфический вид функтора: функтор, который вычисляет логическое значение. Это не обязательно значение bool
тип, а значение типа "булево" семантика. Тип должен быть неявно преобразуемым в bool
хотя.
показанный класс является функтором, реализующим предикат.
о 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:
представляет метод, который определяет набор критериев, и определяет соответствует ли указанный объект этим критериям.