std::function
Храните любые вызываемые объекты
«std::function» — бесплатный урок C++ Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Что такое std::function?
std::function — это оболочка со стиранием типа, способная хранить любой вызываемый объект с заданной сигнатурой: свободные функции, лямбды, функторы или связанные выражения.
- Объявляется с целевой сигнатурой.
- Определен в
<functional>.
#include <iostream>
#include <functional>
int add(int a, int b) { return a + b; }
int main() {
std::function<int(int, int)> f = add;
std::cout << f(2, 3) << '\n';
return 0;
}Хранение лямбды
В отличие от обычного указателя на функцию, std::function без проблем хранит лямбду, даже если она содержит захваты.
#include <iostream>
#include <functional>
int main() {
int offset = 10;
std::function<int(int)> f = [offset](int x) { return x + offset; };
std::cout << f(5) << '\n';
return 0;
}Хранение функтора
Функтор — это объект с operator(). std::function может обернуть его и вызывать его оператор при обращении.
#include <iostream>
#include <functional>
struct Multiplier {
int factor;
int operator()(int x) const { return x * factor; }
};
int main() {
std::function<int(int)> f = Multiplier{3};
std::cout << f(4) << '\n';
return 0;
}Переназначение вызываемого объекта
Одна переменная std::function может указывать на разные вызываемые объекты на протяжении всего времени своего существования, что удобно для замены поведения во время выполнения.
#include <iostream>
#include <functional>
int main() {
std::function<int(int)> f = [](int x) { return x + 1; };
std::cout << f(10) << '\n';
f = [](int x) { return x * x; };
std::cout << f(10) << '\n';
return 0;
}Пустой std::function
Созданный конструктором по умолчанию std::function ничего не хранит. Вызов такого объекта выбрасывает исключение std::bad_function_call, поэтому сначала проверьте его.
#include <iostream>
#include <functional>
int main() {
std::function<void()> f;
if (f) {
f();
} else {
std::cout << "empty\n";
}
return 0;
}В качестве параметра
Функции могут принимать параметр типа std::function, чтобы работать с любым соответствующим вызываемым объектом, делая интерфейсы гибкими.
#include <iostream>
#include <functional>
void repeat(int n, const std::function<void(int)>& action) {
for (int i = 0; i < n; ++i) action(i);
}
int main() {
repeat(3, [](int i) { std::cout << "step " << i << '\n'; });
return 0;
}Хранение функций обратного вызова
Один из распространенных вариантов использования — хранить функцию обратного вызова в члене класса, чтобы вызвать её позже, когда произойдет событие.
#include <iostream>
#include <functional>
struct Button {
std::function<void()> onClick;
void click() { if (onClick) onClick(); }
};
int main() {
Button b;
b.onClick = [] { std::cout << "clicked!\n"; };
b.click();
return 0;
}Вектор вызываемых объектов
Поскольку разные вызываемые объекты имеют один общий тип, их можно хранить вместе в контейнере и вызывать по очереди.
#include <iostream>
#include <functional>
#include <vector>
int inc(int x) { return x + 1; }
int main() {
std::vector<std::function<int(int)>> ops;
ops.push_back(inc);
ops.push_back([](int x) { return x * 2; });
for (auto& op : ops) std::cout << op(10) << ' ';
std::cout << '\n';
return 0;
}Цена стирания типа
std::function может выделять память и добавляет косвенный вызов, поэтому работает немного медленнее прямого вызова или вызываемого объекта, заданного шаблоном. Используйте его, когда Вам нужно единообразное хранение.
#include <iostream>
#include <functional>
int main() {
std::function<int()> f = [] { return 42; };
int total = 0;
for (int i = 0; i < 5; ++i) total += f();
std::cout << total << '\n';
return 0;
}Возврат std::function
Фабрика может создать и вернуть настроенный вызываемый объект, позволяя вызывающему коду получать индивидуальное поведение.
#include <iostream>
#include <functional>
std::function<int(int)> adder(int n) {
return [n](int x) { return x + n; };
}
int main() {
auto add5 = adder(5);
std::cout << add5(10) << '\n';
return 0;
}Сравнение с указателями на функции
std::function гибче указателя на функцию, поскольку хранит состояние, но за эту гибкость приходится платить небольшой потерей производительности и возможным выделением памяти.
#include <iostream>
#include <functional>
int main() {
int base = 7;
std::function<int(int)> stateful = [base](int x) { return x + base; };
std::cout << "Stateful result: " << stateful(3) << '\n';
return 0;
}Быстрая проверка
Проверьте своё понимание std::function.
Повторение
Вы узнали, что std::function:
- оборачивает любой вызываемый объект, соответствующий его сигнатуре, включая лямбды с состоянием и функторы
- может переназначаться, храниться в контейнерах и возвращаться фабриками
- выбрасывает исключение
bad_function_call, когда пуст - добавляет небольшие накладные расходы из-за стирания типа
Далее Вы воспользуетесь std::bind, чтобы заранее заполнить аргументы вызываемых объектов.
Часто задаваемые вопросы
Урок «std::function» бесплатный?
Да — полный текст урока «std::function» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «std::function»?
Храните любые вызываемые объекты Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «std::function»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.