В C++11 добавлены такие пакеты, как std::function, std::bind и лямбда-выражения, чтобы сделать вызовы функций более удобными.
std::function
Прежде чем говорить о std::function, сначала нужно понять, что такое вызываемый объект.
Объект называется вызываемым, если выполняется одно из следующих условий:
- это указатель на функцию
- это объект класса (легендарный функтор) с функцией-членом operator(), лямбда-выражением
- это объект класса, который можно преобразовать в указатель функции
- является указателем члена класса (функции)
- связывать выражения или другие функциональные объекты
И std::function является оболочкой для вышеупомянутого вызываемого объекта.std::function можно рассматривать как объект функции для представления абстрактного понятия функции. Экземпляр std::function может хранить, копировать и вызывать любой вызываемый объект.Сохраненный вызываемый объект называется целью std::function.Если std::function не содержит цели, он называется пустым, а пустой Вызывается std::function Цель ::function вызывает исключение std::bad_function_call.
Используйте следующий пример кода для справки:
std::function<void(int)> f; // 这里表示function的对象f的参数是int,返回值是void
#include <functional>
#include <iostream>
struct Foo {
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_ + i << '\n'; }
int num_;
};
void print_num(int i) { std::cout << i << '\n'; }
struct PrintNum {
void operator()(int i) const { std::cout << i << '\n'; }
};
int main() {
// 存储自由函数
std::function<void(int)> f_display = print_num;
f_display(-9);
// 存储 lambda
std::function<void()> f_display_42 = []() { print_num(42); };
f_display_42();
// 存储到 std::bind 调用的结果
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();
// 存储到成员函数的调用
std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
const Foo foo(314159);
f_add_display(foo, 1);
f_add_display(314159, 1);
// 存储到数据成员访问器的调用
std::function<int(Foo const&)> f_num = &Foo::num_;
std::cout << "num_: " << f_num(foo) << '\n';
// 存储到成员函数及对象的调用
using std::placeholders::_1;
std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
f_add_display2(2);
// 存储到成员函数和对象指针的调用
std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
f_add_display3(3);
// 存储到函数对象的调用
std::function<void(int)> f_display_obj = PrintNum();
f_display_obj(18);
}
Из приведенного выше видно, как используется std::function.Когда std::function заполнен соответствующим списком параметров и возвращаемым значением, он становится оболочкой функции, которая может вместить все такие вызывающие методы. std::function также можно использовать как функцию обратного вызова, или если вам нужно использовать обратный вызов в C++, вы должны использовать std::function, что очень удобно Вы можете прочитать, что я писал о пулах потоков и времени. Статьи по Теме.
std::bind
С помощью std::bind можно связать вызываемый объект и параметры вместе, результат связывания сохраняется с помощью std::function, а вызов откладывается до тех пор, пока он нам не понадобится.
std::bind обычно имеет две функции:
- Свяжите вызываемый объект с аргументами как еще одну функцию std:: для вызова
- Преобразуйте n-арный вызываемый объект в m (m
Конкретный пример:
#include <functional>
#include <iostream>
#include <memory>
void f(int n1, int n2, int n3, const int& n4, int n5) {
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << std::endl;
}
int g(int n1) { return n1; }
struct Foo {
void print_sum(int n1, int n2) { std::cout << n1 + n2 << std::endl; }
int data = 10;
};
int main() {
using namespace std::placeholders; // 针对 _1, _2, _3...
// 演示参数重排序和按引用传递
int n = 7;
// ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001
// 进行到 f(2, 42, 1, n, 7) 的调用
// 嵌套 bind 子表达式共享占位符
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用
// 绑定指向成员函数指针
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 绑定指向数据成员指针
auto f4 = std::bind(&Foo::data, _1);
std::cout << f4(foo) << std::endl;
// 智能指针亦能用于调用被引用对象的成员
std::cout << f4(std::make_shared<Foo>(foo)) << std::endl;
}
лямбда-выражение
Можно сказать, что лямбда-выражение является одной из наиболее важных функций, на которые ссылается C++ 11. Оно определяет анонимную функцию, которая может захватывать определенный диапазон переменных и использовать их внутри функции.Как правило, оно имеет следующий синтаксис:
auto func = [capture] (params) opt -> ret { func_body; };
Где func — это имя, которое можно использовать как лямбда-выражение, используемое как функцию, захват — список захвата, params — список параметров, opt — параметр функции (изменяемый и т. п.), ret — тип возвращаемого значения, а func_body — это тело функции.
Полное лямбда-выражение:
auto func1 = [](int a) -> int { return a + 1; };
auto func2 = [](int a) { return a + 2; };
cout << func1(1) << " " << func2(2) << endl;
Как показано в приведенном выше коде, во многих случаях возвращаемое значение лямбда-выражения очевидно, а С++ 11 позволяет опустить определение возвращаемого значения выражения.
Лямбда-выражения позволяют захватывать переменные в определенной области:
- [] не фиксирует никаких переменных
- [&] Захват ссылки, захват всех переменных во внешней области видимости и использование их в качестве ссылки в теле функции
- [=] захват значения, захват всех переменных во внешней области и использование копии в функции
- Значение [=, &a] захватывает все переменные во внешней области видимости и захватывает переменную по ссылке
- [a] Захватывать только переменную по значению, а не другие переменные
- [this] захватывает указатель this в текущем классе
Пример кода для лямбда-выражения:
int a = 0;
auto f1 = [=](){ return a; }; // 值捕获a
cout << f1() << endl;
auto f2 = [=]() { return a++; }; // 修改按值捕获的外部变量,error
auto f3 = [=]() mutable { return a++; };
F2 в коде не может быть скомпилирован, потому что мы изменяем внешние переменные, захваченные значением. Фактически, лямбда-выражение эквивалентно функтору. Функтор представляет собой объект класса с функцией-членом operator(). Этот оператор() по умолчанию to Это константа, поэтому переменные-члены не могут быть изменены, а добавление mutable означает удаление атрибута const.
Вы также можете использовать лямбда-выражения для настройки правил stl, таких как пользовательское сопоставление сортировки:
struct A {
int a;
int b;
};
int main() {
vector<A> vec;
std::sort(vec.begin(), vec.end(), [](const A &left, const A &right) { return left.a < right.a; });
}
Суммировать
std::function и std::bind упрощают инкапсуляцию функций в нашем обычном процессе программирования, а лямбда-выражения доводят это удобство до крайности.Анонимные функции можно определять на месте, когда это необходимо, без необходимости определять классы или функции. и др., также очень удобны при настройке правил STL, делая код более лаконичным, гибким и повышая эффективность разработки.
использованная литература
this.cpp reference.com/me/cpp/u выносливость…
this.cpp reference.com/me/cpp/u выносливость…
this.cppreference.com/me/cpp/bad-stocks…
this.cppreference.com/me/cpp/that big…
«Углубленное применение C++11: оптимизация кода и приложение инженерного уровня»
«Эффективный современный C++»
Для получения дополнительных статей, пожалуйста, обратите внимание на мой номер принцессы V X: Программа Мяу, добро пожаловать в общение.