Функтор - это, по сути, «функциональный объект». Это отдельная функция, которую вы завернули в класс или структуру, и которую вы можете передать другим функциям.
Они работают, создавая собственный класс или структуру, которая перегружает оператор вызова функции (называемый operator ()). Как правило, вы создаете его экземпляр, просто создавая его на месте в качестве аргумента вашей функции, которая принимает функтор.
Предположим, у вас есть следующее:
std::vector<int> counts;
Теперь вы хотите увеличить все значения, содержащиеся в этом векторе. Вы можете перебрать их вручную, чтобы увеличить их, или использовать функтор. Подходящий функтор в этом случае будет выглядеть так:
struct IncrementFunctor
{
int operator() (int i)
{
return i + 1;
}
}
IncrementFunctor теперь является функтором, который берет любое целое число и увеличивает его. Чтобы применить его к счетчикам, вы можете использовать функцию std :: transform, которая принимает в качестве аргумента функтор.
std::transform(
counts.begin(), // the start of the input range
counts.end(), // the end of the input range
counts.begin(), // the place where transform should place new values.
// in this case, we put it right back into the original list.
IncrementFunctor()); // an instance of your functor
Синтаксис IncrementFunctor () создает экземпляр этого функтора, который затем напрямую передается в std :: transform. Конечно, вы можете создать экземпляр как локальную переменную и передать его, но это гораздо удобнее.
Теперь на шаблоны. Тип функтора в std :: transform является аргументом шаблона. Это потому, что std :: transform не знает (или не заботится!) О типе вашего функтора. Все, что его волнует, - это то, что у него есть определенный оператор fit (), для которого он может сделать что-то вроде
newValue = functor(oldValue);
Компилятор довольно умён в отношении шаблонов и часто может сам определить, каковы аргументы шаблона. В этом случае компилятор автоматически понимает, что вы передаете параметр типа IncrementFunctor, который определен как тип шаблона в std :: transform. Он делает то же самое для списка, поэтому компилятор автоматически распознает, что фактический вызов будет выглядеть следующим образом:
std::transform<std::vector<int>::iterator, // type of the input iterator
std::vector<int>::iterator, // type of the output iterator
IncrementFunctor>( // type of your functor
counts.begin(), // the start of the input range
counts.end(), // the end of the input range
counts.begin(), // the place where transform should place new values.
// in this case, we put it right back into the original list.
IncrementFunctor()); // an instance of your functor
Это сэкономит вам немного времени при наборе текста. ;)