Можно ли передать функцию в качестве аргумента другой функции в C++?

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

Ответ

Да, в C++ функции можно передавать как аргументы. Это фундаментальная возможность, лежащая в основе паттернов обратного вызова (callback), алгоритмов STL и функционального стиля программирования. Есть несколько основных способов:

1. Указатель на функцию (C-стиль):

#include <iostream>

int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }

// Функция, принимающая указатель на функцию как аргумент
int calculate(int x, int y, int (*operation)(int, int)) {
    return operation(x, y);
}

int main() {
    std::cout << calculate(5, 3, &add) << 'n';      // Вывод: 8
    std::cout << calculate(5, 3, multiply) << 'n'; // Вывод: 15 (& необязателен)
    return 0;
}

2. std::function (C++11, более гибко и безопасно):

#include <iostream>
#include <functional>

void greet(const std::string& name) {
    std::cout << "Hello, " << name << '!' << 'n';
}

// Функция, принимающая любой вызываемый объект
void executeCallback(const std::string& arg, const std::function<void(const std::string&)>& callback) {
    callback(arg);
}

int main() {
    executeCallback("World", greet); // Передаем указатель на функцию

    // Можно передавать лямбда-выражение
    executeCallback("User", [](const std::string& s) {
        std::cout << "Callback says: " << s << 'n';
    });
    return 0;
}

3. Шаблоны (для максимальной производительности, устраняют накладные расходы):

template <typename Func>
auto applyOperation(int a, int b, Func op) -> decltype(op(a, b)) {
    return op(a, b);
}

int main() {
    auto result = applyOperation(10, 6, [](int x, int y) { return x - y; });
    std::cout << result << 'n'; // Вывод: 4
    return 0;
}

4. Использование в STL: Это основа работы алгоритмов.

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 2, 8, 1, 9};
    // std::sort принимает компаратор (функцию/лямбду)
    std::sort(vec.begin(), vec.end(), std::greater<int>());
    // vec теперь {9, 8, 5, 2, 1}

    // std::for_each принимает функцию для применения к каждому элементу
    std::for_each(vec.begin(), vec.end(), [](int& n) { n *= 2; });
    // vec теперь {18, 16, 10, 4, 2}
    return 0;
}

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