2016-06-04 8 views
8

В чем разница между использованием функторов и указателями функций. Напримерфункция указатель против функторов в C++

//Functor 
    struct add_x 
    { 
    int x; 
    add_x(int y):x(y){} 
    int operator()(int y) 
    { 
     return x+y; 
    } 
    }; 
    //Function 
    int (func)(int x) 
    { 
    return ++x; 
    } 
    std::vector<int> vec(); 
    //fill vec with 1 2 3 4 5 
    int (*f)(int) = func;//Function pointer 
    std::transform(vec.begin(),vec.end(),f); //approach 1 
    std::transform(vec.begin(),vec.end(),add_x(1)); //approach 2 

Оба подхода работают, но я уверен, что будет иметь место случаи, когда один является предпочтительным (или возможно) над другими.

+0

В вашем примере вы можете заменить 'add_x (1)' на 'add_x (2)'. Чтобы получить такое же изменение с помощью указателя на функцию, вам придется изменить эту функцию. –

+0

, как указано в [ответе на этот вопрос] (http://stackoverflow.com/questions/356950/c-functors-and-their-uses), функторы могут содержать состояние. Например, вы можете написать функтор, который возвращает x + 1 при первом вызове, x + 2 второй раз и т. Д. Конечно, вы можете добиться того же, используя функцию bind, чтобы позволить компилятору превратить функцию с двумя аргументами в функтор с одним аргументом и внешним состоянием. –

+0

Возможный дубликат [Зачем использовать функторы над функциями?] (Https://stackoverflow.com/questions/6451866/why-use-functors-over-functions) – user463035818

ответ

10

Во-первых, функтор может содержать внутреннее состояние; состояние, которое действительно для этого вызова только объекта функции. Вы можете добавить переменные static к вашей функции, но они будут использованы для любого вызова функции.

Во-вторых, компилятор может встроить вызовы в функтор; он не может сделать то же самое для указателя функции. Вот почему C++ std::sort() бьет дерьмо из C qsort() по производительности.

+0

Не могли бы вы объяснить немного больше о том, почему вызов указателя функции не может быть inline ... –

+0

@GauravSehgal: Позвольте мне указать на [этот ответ] (http://stackoverflow.com/questions/2225643). – DevSolar

+0

Вложение, грубо говоря, опирается на определения вызывающих и вызываемых лиц, которые видны компилятору. Передающие указатели функций означают, что компилятор с меньшей вероятностью должен иметь необходимую ему информацию (например, 'qsort()' построен без видимости переданных ему фактических функций). Стилистически, функторы часто используются в обстоятельствах, когда компилятор имеет полную видимость своего определения, поэтому он может встроить. Встраивание функтора можно предотвратить, если компилятор не имеет полной видимости определений (оператора 'operator()' и т. Д.), Которые находятся в другом модуле компиляции. – Peter

0

Функторы могут использоваться даже для эмулирования лямбда-выражений (если вам нужно использовать более старый компилятор до C++ 11/C++ 14), так как они могут иметь индивидуальное состояние (например, в качестве переменных-членов) ,

struct A { 
    int x; // state member can even be made private! Instance per functor possible 
    int operator()(int y) { return x+y } 
}; 

или лямбда

auto lambda = [&x](int y) { return x+y }; 

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

// global scope, anyone can accidentally manipulate and not thread-safe here, only one global instance possible! 
inx x; 
int (func)(int y) { return x+y }; 
+0

Немного назад, потому что C++ имел функторы * до * lambdas. ;-) – DevSolar

+3

@DevSolar: ОП особенно спросил о функторах. Как я уже сказал, вы можете эмулировать lambdas с помощью функторов (например, если у вас есть старший компилятор до C++ 11/C++ 14). Указание этого, очевидно, подразумевает, что функторы старше лямбда. – cwschmidt