Я вижу функциональные объекты, используемые часто вместе с алгоритмами STL. Функциональные объекты появились из-за этих алгоритмов? Когда Вы используете функциональный объект в C++? Каковы его преимущества?
Как сказано в jdv, вместо указателей функций используются функторы, которые сложнее оптимизировать и встроить в компилятор; кроме того, фундаментальным преимуществом функторов является то, что они могут легко сохранять состояние между вызовами к ним 1 , поэтому они могут работать по-разному в зависимости от того, когда они вызывались в другой раз, отслеживать как-то параметры, которые у них есть used, ...
Например, если вы хотите просуммировать все элементы в двух контейнерах int, вы можете сделать что-то вроде этого:
struct
{
int sum;
void operator()(int element) { sum+=element; }
} functor;
functor.sum=0;
functor = std::for_each(your_first_container.begin(), your_first_container.end(), functor);
functor = std::for_each(your_second_container.begin(), your_second_container.end(), functor);
std::cout<<"The sum of all the elements is: "<<functor.sum<<std::endl;
Несколько более точное утверждение состоит в том, что функторы могут поддерживать несколько независимых состояний (функции могут поддерживать одно состояние через статику / глобальные переменные, которые не являются ни поточно-безопасными, ни повторно входимыми).Функторы позволяют использовать еще более сложные состояния, например общее состояние (статические поля) и частное состояние (поля экземпляра). Однако эта дополнительная гибкость используется редко.
Идея инкапсуляции функции как объекта восходит к Lisp и Smalltalk. Идея функтора C ++ была в главе книги Джима Коплиена Advanced C ++ Programming Styles and Idioms в 1991 году. STL использовал идиому и популяризировал ее.
Функциональные объекты были разработаны для обеспечения сильного уровня абстракции над STL, и в этом отношении они великолепны.
Однако я предпочитаю использовать boost :: bind
и вместо этого связывать функцию с алгоритмами STL - обычно (, но не в тех случаях, когда объект имеет состояние ), которое кажется более элегантным решением.
std::for_each( callback.begin(), callback.end(),
boost::bind(&Callback::call(),_1)
);
Кроме того, еще одна предстоящая альтернатива - лямбда-выражения в C ++ 0x (пример, беззастенчиво украденный из Википедии):
std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
total += x;
});
std::cout << total;
Обратите внимание, что из-за замыканий они не имеют ограничение привязки о том, что у них нет государственный.
Я не могу сказать, почему они возникли - возможно, просто потому, что они могли!
Когда вы используете функтор? Учтите, что функтор просто перемещает код, который вы обычно помещаете в цикл, в operator () класса, они не сильно отличаются от простого вызова функции в цикле while ... кроме использования их вы позволяете компилятору встроить код, а также можете передать вместо него предварительно созданный объект, который вы создали с некоторым состоянием. Это последнее обстоятельство делает их очень сильными.
Сравните алгоритм сортировки с вызовом qsort CRT. Они делают то же самое, только по-разному.
Функциональный объект - это функция, которая также является объектом, то есть имеет состояние. Обычные функции обычно не имеют состояния. Они могут имитировать наличие состояния, обращаясь к глобальным переменным, но тогда состояние будет общим для всех вызовов.
Объекты функций (функторы) обычно используются вместо указателей функций. У указателей функций есть проблема: компилятор обычно передает их как необработанные указатели, что затрудняет последующую инкрустацию кода. Кроме того, им легче передавать параметры.