C++ 中,通用的函数适配器 std::bind
是一个强大而灵活的工具。它允许将可调用对象及其参数进行绑定,并生成一个新的可调用对象。在涉及回调机制、延迟函数执行、函数参数部分绑定等场景中,std::bind
的作用尤为突出。
一、什么是 std::bind
?#
std::bind
是 C++ 标准库中的一个模板函数,用来将可调用对象(如普通函数、成员函数、Lambda 函数、仿函数等)与参数绑定在一起,生成一个新的函数对象或 std::function
对象。
其核心函数原型如下:
1
2
|
template< class Fx, class... Args >
function<> bind(Fx&& fx, Args&&... args);
|
Fx
:可调用对象的类型,可以是普通函数、成员函数、Lambda 表达式、仿函数,甚至是另一个 std::function
对象。
Args
:可变参数模板,表示要绑定的参数,可以是值、引用或占位符 std::placeholders::_n
。
返回值:std::bind
返回一个新的可调用对象,通常为 std::function
类型的实例,可以像调用普通函数一样使用。
二、std::bind
的基本用法#
2.1 普通函数的绑定#
普通函数是 std::bind
支持的最基本的可调用对象。通过 std::bind
,我们可以将部分参数绑定,从而生成一个新的函数对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
#include <functional>
void show(int bh, const std::string& message) {
std::cout << "编号 " << bh << ":" << message << std::endl;
}
int main() {
using namespace std::placeholders;
// 绑定普通函数,生成一个新的可调用对象
std::function<void(int, const std::string&)> fn1 = std::bind(show, _1, _2);
fn1(1, "我是一只傻傻鸟。"); // 调用绑定后的函数对象
// 调整参数顺序的绑定
std::function<void(const std::string&, int)> fn2 = std::bind(show, _2, _1);
fn2("我是一只傻傻鸟。", 2); // 交换参数位置后调用
}
|
在这个例子中:
_1
和 _2
是占位符,表示我们可以在调用 fn1
和 fn2
时指定这些参数。
std::bind
返回了一个新的函数对象 fn1
和 fn2
,它们可以接受相应的参数并调用原函数 show
。
三、支持多种可调用对象#
std::bind
可以绑定多种类型的可调用对象,包括普通函数、成员函数、Lambda 表达式、仿函数等。
3.1 绑定静态成员函数#
静态成员函数的本质与普通函数类似,因此可以直接通过 std::bind
进行绑定。
1
2
3
4
5
6
7
8
9
10
11
12
|
struct AA {
static void show(int bh, const std::string& message) {
std::cout << "编号 " << bh << ":" << message << std::endl;
}
};
int main() {
using namespace std::placeholders;
std::function<void(int, const std::string&)> fn3 = std::bind(AA::show, _1, _2);
fn3(2, "我是一只傻傻鸟。");
}
|
3.2 绑定仿函数#
仿函数(即重载了 operator()
的类)也可以通过 std::bind
进行绑定。仿函数常用于自定义函数对象或策略模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
struct BB {
void operator()(int bh, const std::string& message) {
std::cout << "编号 " << bh << ":" << message << std::endl;
}
};
int main() {
using namespace std::placeholders;
BB bb;
std::function<void(int, const std::string&)> fn4 = std::bind(bb, _1, _2);
fn4(3, "我是一只傻傻鸟。");
}
|
3.3 绑定 Lambda 表达式#
Lambda 表达式是 C++11 引入的一种轻量级可调用对象,也可以通过 std::bind
进行部分参数绑定。
1
2
3
4
5
6
7
8
|
int main() {
auto lambda = [](int bh, const std::string& message) {
std::cout << "编号 " << bh << ":" << message << std::endl;
};
std::function<void(int, const std::string&)> fn5 = std::bind(lambda, std::placeholders::_1, std::placeholders::_2);
fn5(4, "我是一只傻傻鸟。");
}
|
3.4 绑定类的非静态成员函数#
绑定非静态成员函数时,必须传递类实例的指针或引用,确保调用时有具体的对象来操作。
1
2
3
4
5
6
7
8
9
10
11
|
struct CC {
void show(int bh, const std::string& message) {
std::cout << "编号 " << bh << ":" << message << std::endl;
}
};
int main() {
CC cc;
std::function<void(int, const std::string&)> fn6 = std::bind(&CC::show, &cc, std::placeholders::_1, std::placeholders::_2);
fn6(5, "我是一只傻傻鸟。");
}
|
在绑定非静态成员函数时,&CC::show
表示成员函数指针,而 &cc
表示该成员函数操作的实例。
3.5 绑定可转换为函数指针的类对象#
通过类型转换操作符,类的实例也可以被转换为函数指针,从而通过 std::bind
进行绑定。
1
2
3
4
5
6
7
8
9
10
11
12
|
struct DD {
using Fun = void (*)(int, const std::string&);
operator Fun() const {
return show;
}
};
int main() {
DD dd;
std::function<void(int, const std::string&)> fn7 = std::bind(dd, std::placeholders::_1, std::placeholders::_2);
fn7(6, "我是一只傻傻鸟。");
}
|
四、std::bind
的参数占位符与参数绑定#
在使用 std::bind
进行绑定时,我们可以选择哪些参数在绑定时固定,哪些参数在调用时动态传入。这里需要使用 std::placeholders::_n
占位符。
_1
, _2
, _3
等占位符用于表示调用时的参数。
- 非占位符参数将在绑定时固定。
1
2
3
4
5
6
7
|
int main() {
using namespace std::placeholders;
// 将第一个参数固定为 3,只需传递剩余的参数
std::function<void(const std::string&)> fn8 = std::bind(show, 3, _1);
fn8("我是一只傻傻鸟。");
}
|
五、总结#
std::bind
是 C++ 中极其强大的函数适配器,它通过绑定可调用对象及其参数生成新的函数对象,从而提供了灵活的参数绑定和调用方式。无论是处理普通函数、成员函数,还是仿函数和 Lambda 表达式,std::bind
都能够简化代码并提高可读性。理解 std::bind
的用法,能够帮助开发者编写更为简洁和通用的代码,尤其是在需要延迟执行、回调函数或函数适配器的场景中。