1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//Листинг #1 Функтор как объект класса с перегруженной операцией () mingw #include <iostream> using std::cout; class Square{ public: int operator() (const int value) const{ return value * value; //возводим в квадрат } }; int main(){ Square sq; cout << sq(10) << '\n'; // 10 * 10 = 100 cout << sq(20) << '\n'; // 20 * 20 = 400 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Литстинг #2.1 Функтор в алгоритме сортировки mingw #include <iostream> #include <algorithm> using namespace std; bool compare(const int left, const int right){ //сама функция не функтор, потому что она в терминах С++ не объект return left < right; //если left меньше right, вернётся true, иначе вернётся false } int main(){ int arr[] = {1,2,3,4,5}; sort(begin(arr), end(arr), compare); //но имя функции "compare" — функтор, оно приводится к указателю, а указатель — объект } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//Литстинг #2.2 Функтор в алгоритме сортировки mingw #include <iostream> #include <algorithm> using namespace std; class Less{ //сам класс не объект, он не функтор public: bool operator() (const int left, const int right){ //а для его будущего объекта перегружена (), объект будет функтором return left < right; } }; int main(){ int arr[] = {1,2,3,4,5}; Less less; //создаём объект, который благодаря перегруженным круглым скобкам — функциональный объект, т. е. функтор sort(begin(arr), end(arr), less); //передаём функтор в алгоритм сортировки } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//Литстинг #2.3 Функтор в алгоритме сортировки mingw #include <iostream> #include <algorithm> using namespace std; bool compare(const int left, const int right){ //сама функция не функтор, потому что она в терминах С++ не объект return left < right; //если left меньше right, вернётся true, иначе вернётся false } int main(){ int arr[] = {1,2,3,4,5}; bool (*p)(int, int); p = compare; //p — указатель на функцию, направлен на compare sort(begin(arr), end(arr), p); //алгоритмы умеют принимать и указатели на функции //указатели на функции — это функторы } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
//Литстинг #3 Функторы не всегда заменяют указатели на функции mingw #include <iostream> using namespace std; void foo(void (*)()){ //функция принимает указатель на функцию с пустым списком параметров std:: cout << "foo\n"; } void f1(){ cout << "f1\n"; } struct Functor{ void operator() (){} }; int main(){ foo(f1); //OK, имя f1 неявно привелось к указателю (функция f1 не задействована) void (*ptr)() = f1; //создали явный указатель на функцию и направали его на foo foo(ptr); //передали созданный указатель функции, OK Functor functor; foo(functor); //объект класса не умеет преобразовываться к указателю, НОУ!!! ошибка компиляции } |
Когда мы используем алгоритм сортировки из стандартной библиотеки шаблонов, то нам нужно задавать какой-то критерий, в каком случае делать перестановку, а в каком не делать. В зависимости от текущей на момент ситуации (от расстановки элементов) нам требуется только два ответа: надо выполнять перестановку или нет, для этого мы используем функцию, благодаря которой происходит анализ ситуации и отдаётся признак необходимости перестановки — если ответ true, то надо, а если false, то не надо. Предикат — это просто утверждение, в нашем случае утверждение о нужности или игноре выполнени какого-то действия. Таким образом, в листинге #2.1 функция compare предикат, потому что возвращает признак надобности в виде булева значения, а в листинге #2.2. перегруженная операция () предикат, потому что возвращает признак надобности в виде булева значения. Т. е. любая функция, которая возвращает значение с типом bool или используется как функция, возвращающая значение с типом bool — предикат. Но учтите, что не каждый предикат функтор, и не каждый функтор — предикат. Уже об этом говорилось, но повторюсь, обычная функция не объект и не считается функтором, но вполне может быть предикатом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//Листинг #4 Существует некоторое множество уже готовых функторов, описаны они в functional mingw #include <iostream> #include <functional> #include <algorithm> using namespace std; void print(const int i){ //для вывода на экран функторов в functional нет, cout << i << ' '; //используем свою функцию } int main(){ int arr[] = {1,2,3,4,5}; sort(begin(arr), end(arr), greater<int>()); //функтор сравнения, if (x > y) - перестановка for_each(begin(arr), end(arr), print ); //используем имя своей функции в качестве функтора cout << '\n'; sort(begin(arr), end(arr), less<int>()); //функтор сравнения, if (x < y) - перестановка for_each(begin(arr), end(arr), print ); } |
В functional описаны функторы для сравнения, для арифметических операций, для логических операций и некоторые другие.
1 2 3 4 5 |
//Пример пустой лямбда-функции int main(){ [](){}; } |
Такие лямбда-функции легко встраиваются в любое место, где нужен функтор, и даже могут использоваться просто как функции, но это уже немного другая тема, поэтому просто принимайте к сведению, что лямбда-функции — это функторы. Например, для алгоритма for_each мы могли бы не описывать отдельно функтор, а впаять непосредственно в место для функтора лямбда-функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//Листинг #5 Использование функтора лямбда-функция mingw #include <iostream> #include <algorithm> using namespace std; int main() { int arr[10] = {1,2,3,4,5,6,7,8,10}; for_each(begin(arr), end(arr), [](const int i){ cout << i << ' '; }); } |
haha
«Функторы имеют свойсто быть пересылаемыми и присваиваемыми, поскольку они объекты; обычные функции таким свойством не обладают.»
Это почему указатели на функции не могут быть пересылаемыми и присваемыми?
А при чём тут указатели на функции, если в цитируемом речь идёт о функциях?