std::bind 是 C++11 引入的函数适配器 ,定义在 <functional> 头文件中,核心作用是将函数与参数绑定,生成一个可调用对象。它可以延迟函数调用、固定部分参数、修改函数调用形式,是 C++ 中实现函数参数绑定、回调函数封装的核心工具。
本文从基础用法、参数绑定、占位符、绑定成员函数、实战场景等维度,系统讲解 std::bind 的使用方法与原理。
一、std::bind 基础概念
1. 占位符基本用法
#include <iostream> #include <functional> void show(int a, int b, int c) { std::cout << a << " " << b << " " << c << std::endl; } int main() { using namespace std::placeholders; // 简化占位符使用 // _1:第一个动态参数,_2:第二个动态参数 auto func = std::bind(show, _1, 100, _2); func(10, 20); // 输出:10 100 20 // 调整参数顺序:交换 _1 和 _2 auto func_swap = std::bind(show, _2, _1, 30); func_swap(10, 20); // 输出:20 10 30 return 0; }
2. 占位符与固定参数混合
-
本质 :
std::bind是一个模板函数,接收一个可调用对象(普通函数、函数指针、lambda、成员函数、仿函数)和若干参数,返回一个新的可调用对象。 -
核心能力 :
- 固定函数的部分参数(参数绑定);
- 调整参数的顺序;
- 将成员函数转换为普通可调用对象;
- 延迟函数执行。
-
头文件 :使用前必须包含
cpp#include <functional>二、基础用法:绑定普通函数
1. 无参数绑定(直接封装函数)
直接用
bind封装无参函数,生成可调用对象,调用时执行原函数。cpp#include <iostream> #include <functional> // 必须包含 // 普通无参函数 void print() { std::cout << "Hello std::bind!" << std::endl; } int main() { // 绑定函数,生成可调用对象 func auto func = std::bind(print); func(); // 调用:输出 Hello std::bind! return 0; }2. 固定参数(绑定实参)
绑定函数时直接传入参数值,调用时无需重复传参,参数被永久固定。
cpp#include <iostream> #include <functional> // 带参数的普通函数 int add(int a, int b) { return a + b; } int main() { // 绑定 add 函数,固定参数 10 和 20 auto add_10_20 = std::bind(add, 10, 20); std::cout << add_10_20() << std::endl; // 输出:30 // 固定第一个参数为 5,第二个参数后续传入 auto add_5 = std::bind(add, 5, std::placeholders::_1); std::cout << add_5(15) << std::endl; // 输出:20(5+15) return 0; }三、占位符:std::placeholders
std::placeholders是std::bind的参数占位符 ,用_1、_2、_3...表示调用时才传入的参数,用于: -
保留参数位置;
-
调整参数顺序;
-
动态传参。
cpp
#include <iostream>
#include <functional>
void show(int a, int b, int c) {
std::cout << a << " " << b << " " << c << std::endl;
}
int main() {
using namespace std::placeholders; // 简化占位符使用
// _1:第一个动态参数,_2:第二个动态参数
auto func = std::bind(show, _1, 100, _2);
func(10, 20); // 输出:10 100 20
// 调整参数顺序:交换 _1 和 _2
auto func_swap = std::bind(show, _2, _1, 30);
func_swap(10, 20); // 输出:20 10 30
return 0;
}
_1对应调用时的第一个实参 ,_2对应第二个实参,以此类推;- 占位符的数量没有上限,根据函数参数个数灵活使用。
2. 占位符与固定参数混合
绑定函数时,可混合使用固定值和占位符,灵活控制参数:
cpp
// 函数:a - b
int sub(int a, int b) { return a - b; }
int main() {
using namespace std::placeholders;
// 固定 b=5,a 动态传入
auto sub_5 = std::bind(sub, _1, 5);
std::cout << sub_5(20) << std::endl; // 20-5=15
// 固定 a=30,b 动态传入
auto sub_30 = std::bind(sub, 30, _1);
std::cout << sub_30(10) << std::endl; // 30-10=20
return 0;
}
四、进阶用法:绑定类成员函数
std::bind 最常用的场景之一是绑定类的成员函数 。注意:类成员函数隐含 this 指针 ,绑定时必须传入对象(或对象指针 / 引用) 作为第一个参数。
1. 绑定普通成员函数
cpp
#include <iostream>
#include <functional>
#include <string>
class Person {
private:
std::string name;
public:
Person(std::string n) : name(n) {}
// 成员函数
void showInfo(int age) {
std::cout << "姓名:" << name << ",年龄:" << age << std::endl;
}
};
int main() {
using namespace std::placeholders;
Person p("张三"); // 创建对象
// 绑定成员函数:第一个参数是 &成员函数,第二个参数是对象地址/对象
auto func = std::bind(&Person::showInfo, &p, _1);
func(20); // 输出:姓名:张三,年龄:20
// 直接传对象(会拷贝对象)
auto func2 = std::bind(&Person::showInfo, p, 25);
func2(); // 输出:姓名:张三,年龄:25
return 0;
}
2. 绑定静态成员函数
静态成员函数无 this 指针,绑定时无需传入对象,直接使用类名调用:
cpp
class Test {
public:
static void staticFunc(int a) {
std::cout << "静态函数:" << a << std::endl;
}
};
int main() {
auto func = std::bind(&Test::staticFunc, std::placeholders::_1);
func(100); // 输出:静态函数:100
return 0;
}
五、绑定仿函数与 lambda 表达式
std::bind 支持绑定所有可调用对象,包括仿函数(函数对象) 和 lambda 表达式:
cpp
#include <iostream>
#include <functional>
// 仿函数
struct Multiply {
int operator()(int a, int b) {
return a * b;
}
};
int main() {
// 1. 绑定仿函数
Multiply mul;
auto func1 = std::bind(mul, 6, 7);
std::cout << func1() << std::endl; // 42
// 2. 绑定 lambda 表达式
auto lambda = [](int a, int b) { return a + b; };
auto func2 = std::bind(lambda, std::placeholders::_1, 8);
std::cout << func2(12) << std::endl; // 20
return 0;
}
六、std::bind 与 std::function 配合使用
std::function 是可调用对象的包装器,std::bind 生成的可调用对象可以存入 std::function,实现统一的函数接口管理(常用于回调函数、事件处理)
cpp
#include <iostream>
#include <functional>
// 回调函数类型:int -> int
using Callback = std::function<int(int)>;
int square(int x) { return x * x; }
// 接收回调函数
void process(int num, Callback cb) {
std::cout << "结果:" << cb(num) << std::endl;
}
int main() {
// 用 bind 封装函数,传入 std::function
auto func = std::bind(square, std::placeholders::_1);
process(5, func); // 输出:结果:25
return 0;
}
七、注意事项
八、总结
std::bind 是 C++ 中强大的函数适配器,核心价值是灵活绑定函数与参数,简化可调用对象的封装与调用。
掌握 std::bind,能大幅提升 C++ 中函数封装、回调机制的代码灵活性与可读性。
总结
-
参数拷贝 :
std::bind绑定参数时,默认会拷贝参数值 。如果需要传递引用,必须使用std::ref(引用)或std::cref(常量引用):cppvoid setValue(int& a) { a = 100; } int main() { int x = 0; auto func = std::bind(setValue, std::ref(x)); // 必须用 ref 传递引用 func(); std::cout << x << std::endl; // 输出:100 return 0; } -
占位符作用域 :占位符
_1、_2...位于std::placeholders命名空间下,建议使用using namespace std::placeholders;简化代码。 -
成员函数绑定 :必须取地址
&类名::成员函数,且第一个参数必须是对象 / 对象指针。 -
替代方案 :C++11 之后,lambda 表达式 可以替代大部分
std::bind简单场景,但bind在绑定成员函数、灵活调整参数顺序时更简洁。 -
基础:绑定普通函数,固定参数、动态传参;
-
核心:
std::placeholders占位符,控制参数位置与顺序; -
std::bind是 C++11 函数适配器,用于生成可调用对象,需包含<functional>头文件; -
核心用法:绑定普通函数 / 成员函数 / 仿函数,用
_1、_2占位符实现动态传参、调整参数顺序; -
绑定成员函数必须传入对象 / 指针,传引用需用
std::ref; -
常与
std::function配合,用于回调函数、参数固定、延迟调用等场景。- 重点:绑定类成员函数,必须传入对象 / 指针;
- 实战:配合
std::function实现回调函数、统一接口管理。