Что такое функтор (Functor) в C++?

«Что такое функтор (Functor) в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Функтор (или объект-функция) в C++ — это объект класса, для которого перегружен оператор вызова operator(). Это позволяет использовать объект так, как будто он является функцией.

Простой пример:

struct Multiplier {
    int factor;
    Multiplier(int f) : factor(f) {} // Конструктор сохраняет состояние
    // Перегрузка оператора вызова функции
    int operator()(int x) const {
        return x * factor;
    }
};

int main() {
    Multiplier multiplyBy5(5);
    Multiplier multiplyBy3(3);

    std::cout << multiplyBy5(10); // Выведет 50. Вызов obj(10) -> obj.operator()(10)
    std::cout << multiplyBy3(7);  // Выведет 21

    // Функторы легко работают с алгоритмами STL
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::transform(vec.begin(), vec.end(), vec.begin(), multiplyBy5);
    // vec теперь содержит {5, 10, 15, 20, 25}
}

Ключевые преимущества функторов перед указателями на функции:

  • Сохранение состояния: Функтор может иметь поля-члены (как factor в примере), что делает его более гибким.
  • Возможность инлайнинга: Компилятор может легко встроить вызов operator(), что часто приводит к более эффективному коду по сравнению с вызовом через указатель на функцию.
  • Полиморфизм: Функтор может быть полиморфным, используя виртуальные методы в operator().

Связь с лямбда-выражениями: Начиная с C++11, лямбда-выражения — это синтаксический сахар для анонимных функторов. Компилятор преобразует лямбду в уникальный класс с operator().

// Эта лямбда...
auto lambda = [factor=5](int x) { return x * factor; };
// ...примерно эквивалентна такому функтору:
struct __AnonymousLambda {
    int factor;
    int operator()(int x) const { return x * factor; }
};

Функторы остаются полезными, когда нужна сложная инициализация, наследование или когда тип должен быть явно именован.