Когда вы используете функциональные объекты в C ++? - PullRequest
11 голосов
/ 28 февраля 2010

Я вижу функциональные объекты, часто используемые вместе с алгоритмами STL. Появились ли функциональные объекты из-за этих алгоритмов? Когда вы используете функциональный объект в C ++? В чем его преимущества?

Ответы [ 7 ]

9 голосов
/ 28 февраля 2010

Как сказал jdv, вместо указателей функций используются функторы, которые сложнее оптимизировать и встроить в компилятор; кроме того, фундаментальное преимущество функторов заключается в том, что они могут легко сохранять состояние между вызовами к ним 1 , поэтому они могут работать по-разному в зависимости от того, в какой раз они были вызваны, как-то отслеживать параметры, которые у них есть используется, ...

Например, если вы хотите сложить все элементы в два контейнера целых чисел, вы можете сделать что-то вроде этого:

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;

  1. На самом деле, как указал Р. Самуэль Клатчко ниже, они могут поддерживать несколько независимых состояний, по одному для каждого экземпляра функтора:
    Несколько более точное утверждение состоит в том, что функторы могут поддерживать несколько независимых состояний (функции могут поддерживать одно состояние через statics / globals, который не является ни потокобезопасным, ни реентерабельным).
    Функторы позволяют использовать даже более сложные состояния, например общее состояние (статические поля) и приватное состояние (поля экземпляра). Однако эта дополнительная гибкость используется редко.
8 голосов
/ 28 февраля 2010

Функциональные объекты (функторы) обычно используются вместо указателей функций. Проблема с указателями на функции заключается в том, что компилятор обычно передает их как необработанные указатели, что затрудняет компилятору встроенный код позже. И им проще давать параметры.

2 голосов
/ 28 февраля 2010

Идея инкапсуляции функции как объекта восходит к Lisp и Smalltalk. Идея функтора на C ++ была главой в книге Джима Коплиена Усовершенствованные стили программирования и идиомы C ++ в 1991 году. STL использовала эту идиому и в дальнейшем популяризовала ее.

2 голосов
/ 28 февраля 2010

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

2 голосов
/ 28 февраля 2010

Функциональные объекты были разработаны, чтобы обеспечить сильный уровень абстракции над STL, и в этом отношении они великолепны.

Однако я предпочитаю использовать boost::bind и вместо этого связывать функцию с алгоритмами STL - обычно (, хотя не в тех случаях, когда объект имеет состояние ), что кажется более элегантным решением. 1006 *

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;

Обратите внимание, что из-за замыканий они не имеют ограничения ограничения на отсутствие состояния.

1 голос
/ 03 апреля 2013

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

1 голос
/ 28 февраля 2010

Я не могу сказать, почему они появились - возможно, просто потому, что они могли!

Когда вы используете функтор? Учтите, что функтор просто перемещает код, который вы обычно помещаете в цикл, в оператор () класса, он не сильно отличается от простого вызова функции в цикле while ... за исключением использования их вы позволяете компилятору встроить код, а также можете вместо этого передавать предварительно созданный объект, который вы создали с некоторым состоянием. Этот последний момент делает их очень сильными.

Сравните алгоритм сортировки с вызовом CRTs qsort. Они делают то же самое, только делают это совсем по-другому.

...