0%

std::function和std::bind

std::functionstd::bind 是 C++11 标准库中引入的两个重要组件,用于实现函数对象的封装和绑定。它们为 C++ 中的函数式编程提供了更加灵活和方便的方式。可以用于实现回调函数的思想。

std::function

std::function 是一个模板类,用于封装任意可调用对象(函数指针、函数对象、成员函数指针、lambda 表达式等),并提供一种统一的接口来调用这些对象。它可以看作是一个类型安全的函数指针的容器。

特点:

  • std::function 是可调用对象的包装器,它可以存储、复制和调用任何可调用对象。
  • std::function 的类型由其模板参数确定,因此它可以表示各种不同的函数类型。
  • std::function 对象可以在运行时被赋予不同的可调用对象,并且可以被多次复制、传递和调用。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <functional>

void say_hello() {
std::cout << "Hello, world!" << std::endl;
}

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

int main() {
std::function<void()> func1 = say_hello;
func1(); // 调用 say_hello 函数

std::function<int(int, int)> func2 = add;
std::cout << "Sum: " << func2(3, 4) << std::endl; // 调用 add 函数

return 0;
}

std::bind

std::bind 是一个函数模板,用于创建一个新的可调用对象。该对象会将参数绑定到函数或函数对象上。它允许延迟绑定参数,以后再调用时传递剩余的参数。

语法:

1
2
3
#include <functional>

auto new_function = std::bind(function, arg1, arg2, ...);
  • function:要绑定的函数或函数指针。
  • arg1, arg2, ...:要绑定到函数的参数。

特点:

  • std::bind 可以绑定函数的部分或全部参数,从而创建一个新的可调用对象。
  • std::bind 返回的可调用对象可以被多次复制、传递和调用。
  • std::bind 可以绑定参数的位置,也可以绑定参数的值,还可以使用占位符 _1_2 等来表示未指定的参数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <functional>

void greet(const std::string& name, int age) {
std::cout << "Hello, " << name << "! You are " << age << " years old." << std::endl;
}

int main() {
auto greet_function = std::bind(greet, "Alice", std::placeholders::_1);
greet_function(30); // 输出:Hello, Alice! You are 30 years old.

auto add_function = std::bind(std::plus<int>(), std::placeholders::_1, std::placeholders::_2);
std::cout << "Sum: " << add_function(3, 4) << std::endl; // 输出:Sum: 7

return 0;
}

在这个示例中,std::bind 函数用来创建一个新的可调用对象 greet_function,它绑定了 greet 函数的第一个参数为 “Alice”,第二个参数由调用者传入。而另一个可调用对象 add_function 绑定了 std::plus<int>() 函数对象,表示对两个参数进行加法运算。

假设我们有一个事件循环,当某个定时器超时时,我们需要执行一个回调函数,并传递一些参数给这个回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <functional>
#include <chrono>
#include <thread>

void callback(const std::string& message, int value) {
std::cout << message << ": " << value << std::endl;
}

int main() {
// 定义一个 std::function 对象,用来存储回调函数
std::function<void()> func;

// 使用 std::bind 创建一个绑定了参数的可调用对象,并将其赋值给 func
func = std::bind(callback, "Callback message", 42);

// 模拟定时器超时,当定时器超时时调用回调函数
std::this_thread::sleep_for(std::chrono::seconds(2));
func(); // 调用回调函数

return 0;
}

function与bind的结合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <functional>

// 普通函数
void freeFunction(int a) {
std::cout << "Free function called with " << a << std::endl;
}

// 函数对象
struct Functor {
void operator()(int a) const {
std::cout << "Functor called with " << a << std::endl;
}
};

// 成员函数
class MyClass {
public:
void memberFunction(int a) {
std::cout << "Member function called with " << a << std::endl;
}
};

int main() {
// 使用std::function包装普通函数
// std::function<void(int)> func1 = freeFunction;
std::function<void(int)> func1 = std::bind(freeFunction, std::placeholders::_1);
func1(1);

// 使用std::function包装函数对象
// std::function<void(int)> func2 = Functor();
Functor functor;
std::function<void(int)> func2 = std::bind(functor, std::placeholders::_1);
func2(2);

// 使用std::function包装lambda表达式
std::function<void(int)> func3 = [](int a) {
std::cout << "Lambda called with " << a << std::endl;
};
func3(3);

// 使用std::function包装成员函数
MyClass obj;
// std::function<void(MyClass*, int)> func4 = &MyClass::memberFunction;
// func4(&obj, 4);
std::function<void(int)> func4 = std::bind(&MyClass::memberFunction, &obj, std::placeholders::_1);
func4(4);

return 0;
}

占位符std::placeholders

用来表示未绑定的参数。这些占位符在 std::placeholders 命名空间中定义。常见的占位符有:

  • std::placeholders::_1:表示调用时传递的第一个参数。
  • std::placeholders::_2:表示调用时传递的第二个参数。
  • 以此类推,可以使用 _3, _4 ….等表示更多的参数。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <functional>

// 普通函数
void exampleFunction(int a, int b, int c) {
std::cout << "Called with a=" << a << ", b=" << b << ", c=" << c << std::endl;
}

int main() {
// 使用std::bind绑定部分参数
std::function<void(int)> boundFunction = std::bind(exampleFunction, std::placeholders::_1, 100, std::placeholders::_2);

// 调用绑定的函数
boundFunction(10, 20); // 实际调用exampleFunction(10, 100, 20)

return 0;
}
1
std::function<void(int)> boundFunction = std::bind(exampleFunction, std::placeholders::_1, 100, std::placeholders::_2);

这行代码创建了一个新的可调用对象 boundFunction,它绑定了 exampleFunction 的第二个参数 b 为 100,而第一个参数 a 和第三个参数 c 使用占位符 _1_2,表示它们将在调用 boundFunction 时传递。