
文章目录
- 引言
- 1.std::function
- 2.std::bind
- 3.实战案例
-
- [3.1.逆波兰表达式求值(function + map优化版本)](#3.1.逆波兰表达式求值(function + map优化版本))
- 3.2.复利计算
- 4.注意事项
- 结语
引言
在C++中,可调用对象类型五花八门(函数指针、仿函数、lambda表达式、类成员函数等),它们的逻辑功能十分相似,但是类型差异巨大,导致代码声明繁琐、接口适配困难、扩展性不足。而C++11通过引入
std::function包装器,抹平了不同类型间的差异;引入std::bind包装器,灵活调整参数列表,以适配各种接口。
1.std::function
1.1.什么是std::function
std::function是C++11提供的类模板包装器 ,定义在<functional>头文件中,核心作用是消除不同可调用对象的类型差异。无论是普通函数、lambda还是仿函数,都能被std::function包装成同一类型。
cpp
template <class Ret, class... Args>
class function<Ret(Args...)>;
Ret:可调用对象的返回值类型Args...:可调用对象的参数列表
1.2.核心用法
1.2.1.包装普通函数
普通函数是最基础的可调用对象:
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
int add(int a, int b)
{
return a + b;
}
int main()
{
//包装add函数,类型匹配int<int, int>
function<int(int, int)> func_add = add;
cout << "1 + 2 = " << func_add(1, 2) << endl;
return 0;
}
运行结果:

1.2.2.包装仿函数
仿函数是重载operator()的类实例
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
struct Sub {
int operator()(int a, int b)
{
return a - b;
}
};
int main()
{
function<int(int, int)> func_sub = Sub();
cout << "5 - 3 = " << func_sub(5, 3) << endl;
return 0;
}
运行结果:

1.2.3.包装lambda表达式
lambda是匿名函数对象,function能直接与之匹配
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
int main()
{
function<int(int, int)> func_mul = [](int a, int b) {return a * b;};
cout << "3 * 4 = " << func_mul(3, 4) << endl;
return 0;
}
运行结果:

1.2.4.包装类成员函数
包装类成员函数需要额外处理this指针,function需在参数列表中显式声明this对应的对象类型(指针或引用 );
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
class Divide {
public:
//非静态成员函数,参数隐含this指针
double div(double a, double b)
{
return a / b;
}
//静态成员函数,不含this指针
static double div_static(double a, double b)
{
return a / b;
}
};
int main()
{
Divide d;
//包装非静态成员函数,包含this指针
function<double(Divide*, double, double)> func_div = &Divide::div;//非静态成员函数必须取地址,不能隐式类型转换
cout << "func_div: " << "12.2 / 2 = " << func_div(&d, 12.2, 2) << endl;
//包装静态成员函数,不包含this指针
function<double(double, double)> func_stat_div = Divide::div_static;//取地址可加可不加
cout << "func_stat_div: " << "12.2 / 2 = " << func_stat_div(12.2, 2) << endl;
return 0;
}
运行结果:

1.2.5.空包装器
若std::function是空包装器(未绑定任何可调用对象),调用时会抛异常(std::bad_function_call),注意捕获。
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
int main()
{
function<int(int, int)> func_empty;
try {
func_empty(3, 4);
}
catch (const bad_function_call& e) {
cout << "error: " << e.what() << endl;
}
return 0;
}
运行结果:

1.3.什么时候适合用std::function
- 作为容器元素:如
map<string,function<Arg...>>,实现字符串-函数映射。 - 作为函数参数/返回值:传递回调函数时,不需要关注函数的具体类型(函数指针/仿函数/lambda),匹配函数签名(返回值类型、参数类型和数量)即可。
- 简化类型声明:替代复杂的函数指针类型,如:
int(*)(int ,int),代码更简洁。
2.std::bind
2.1.什么是std::bind
std::bind是C++11提供的函数模板 ,定义在<functional>头文件中,核心作用是调整可调用对象的参数列表(绑定固定参数、重新排序参数)
cpp
//simple(1)
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
//with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
一般形式:auto newCallable = bind(callable, arg_list)
- callable:原可调用对象
- arg_list:参数列表
- 参数列表中,
placeholders::_n(如_1、_2)是占位符,表示新函数的第n个参数,未用占位符的参数会被"固定绑定"。
2.2.核心用法
2.2.1.绑定固定参数(减少参数)
假设我们有一个计算乘法的函数mul,如果我们想固定其中一个因数a为100, 只用输入另一个因数b,此时可用bind 实现
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
int mul(int a, int b)
{
return a * b;
}
int main()
{
//绑定_a == 100, 新函数第一个参数_1传给b
auto mul_fixed_a = bind(mul, 100, _1);
cout << "100 * 5 = " << mul_fixed_a(5) << endl;
////绑定_b == 200, 新函数第一个参数_1传给a
auto sub_fixed_b = bind(mul, _1, 200);
cout << "3 * 200 = " << mul_fixed_a(3) << endl;
return 0;
}
运行结果:

2.2.2.重排参数顺序
如果要调整函数参数顺序,可以通过调整占位符顺序实现
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
int sub(int a, int b)
{
return a - b;
}
int main() {
// 原函数是 a - b,重排后变成 b - a(_2 是新函数第2个参数,_1 是第1个)
auto sub_swap = bind(sub, _2, _1);
cout << "5 - 10 = " << sub_swap(10, 5) << endl; // 输出:(5-10)*10=-50
return 0;
}
运行结果:

2.2.3.结合成员函数使用
非静态成员函数中参数包含隐藏的this指针 ,因此bind绑定时需要包含该类的引用或指针参数
代码示例:
cpp
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
class Calculator {
public:
double multiply(double a, double b) {
return a * b;
}
};
int main() {
Calculator calc;
// 绑定 calc 作为 this 指针,_1 和 _2 是新函数的两个参数
auto calc_mul = bind(&Calculator::multiply, &calc, _1, _2);
cout << "3 * 4 = " << calc_mul(3, 4) << endl; // 输出:12
return 0;
}
运行结果:

2.3.什么时候适合用std::bind
- 适配参数不匹配的接口:比如一个第三方库函数需要传三个参数,但我的函数只有两个参数,这时可以用bind绑定一个参数,即可适配
- 简化重复调用:若某函数频繁用相同参数调用,可以用bind绑定,简化函数
3.实战案例
3.1.逆波兰表达式求值(function + map优化版本)
function + map --> "操作符 - 函数"映射
代码示例:
cpp
#include <stack>
#include <vector>
#include <string>
#include <functional>
#include <map>
using namespace std;
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
// 用 map 存储"操作符-function"映射
map<string, function<int(int, int)>> op_map = {
{"+", [](int a, int b) { return a + b; }},
{"-", [](int a, int b) { return a - b; }},
{"*", [](int a, int b) { return a * b; }},
{"-", [](int a, int b) { return a - b; }},
{"/", [](int a, int b) { return a / b; }},
{"%", [](int a, int b) { return a % b; }}
};
for (auto& str : tokens) {
if (op_map.count(str)) { // 匹配到操作符
int right = st.top(); st.pop();
int left = st.top(); st.pop();
// 调用对应的 function
st.push(op_map[str](left, right));
}
else {
st.push(stoi(str));
}
}
return st.top();
}
};
3.2.复利计算
在计算复利时,需要传入三个参数:利率、本金、年限,如果我们想固定利率和年限,只输入本金,则可用bind简化函数。
代码示例:
cpp
#include <functional>
#include <iostream>
using namespace std;
using namespace placeholders;
int main() {
// 复利计算 lambda:rate=年利率,money=本金,year=年限,返回利息
auto calc_interest = [](double rate, double money, int year) -> double {
double ret = money;
for (int i = 0; i < year; i++) {
ret += ret * rate; // 每年复利
}
return ret - money; // 利息 = 最终金额 - 本金
};
// 用 bind 固定利率和年限,生成专用函数(只需传入本金)
function<double(double)> interest_3y_1_5 = bind(calc_interest, 0.015, _1, 3); // 3年1.5%利率
function<double(double)> interest_5y_2_0 = bind(calc_interest, 0.020, _1, 5); // 5年2.0%利率
function<double(double)> interest_10y_2_5 = bind(calc_interest, 0.025, _1, 10); // 10年2.5%利率
// 调用简化版函数
cout << "100万 3年1.5%利息:" << interest_3y_1_5(1000000) << endl; // 约45678.38
cout << "100万 5年2.0%利息:" << interest_5y_2_0(1000000) << endl; // 约104080.80
cout << "100万 10年2.5%利息:" << interest_10y_2_5(1000000) << endl; // 约280084.50
return 0;
}
运行结果:

4.注意事项
- function非静态成员函数时,由于非静态成员函数参数中隐藏了this指针,因此function参数列表必须包含
this指针对应的对象类型(指针或引用),否则编译报错。 - bind占位符 在命名空间
std::placeholders中,使用前记得显式声明using namespace std::placeholders。 - 若用bind绑定引用参数,需用
ref()或cref()包装,否则bind会默认按值传递。
cpp
void print(int& x) { x++; cout << x << endl; }
int main() {
int a = 10;
auto func = bind(print, ref(a)); // 用 ref 绑定引用
func(); // 输出 11,a 被修改为 11
return 0;
}
- 包装器底层是函数对象封装,无额外性能消耗,不必担心效率问题。
结语
std::function 和 std::bind 作为 C++11 引入的强大工具,共同为处理复杂的函数调用场景带来了革命性的简化:它们消除了不同可调用对象(如普通函数、Lambda 表达式、成员函数)之间的类型壁垒,使得函数的传递、存储和调用变得前所未有的统一和灵活。开发者无需再为每种回调类型定义繁琐的函数指针或适配器,std::function 提供了一个通用的 "容器",而 std::bind 则像一个万能的 "适配器",能够轻松调整函数签名,固定参数或重排参数顺序,极大地提升了代码的表达力和可维护性。