1. 为什么需要函数包装器
在C++开发中,我们经常遇到需要处理不同类型可调用对象的情况。传统C风格的函数指针虽然可以指向函数,但存在明显的局限性:
cpp复制// 传统函数指针示例
int add(int a, int b) { return a + b; }
int (*funcPtr)(int, int) = add;
cout << funcPtr(2, 3) << endl; // 输出5
这种方式的缺点很明显:
- 无法指向lambda表达式
- 无法指向重载了operator()的类对象(仿函数)
- 处理成员函数时需要特殊语法
- 类型安全性较差
C++11引入的std::function完美解决了这些问题。它就像是一个万能容器,可以存储任何符合签名的可调用对象。想象一下,你有一个工具箱,以前只能放扳手,现在可以放扳手、螺丝刀、锤子等各种工具,而且取用时不需要关心具体是什么工具。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. std::function的深度解析
2.1 基本语法与模板参数
std::function的声明形式如下:
cpp复制#include <functional>
std::function<返回类型(参数类型列表)> 对象名;
这里的模板参数非常关键,它决定了这个function对象能包装什么样的可调用对象。例如:
cpp复制std::function<int(int, int)> func; // 可以包装任何接受两个int返回int的可调用对象
2.2 包装不同类型的可调用对象
让我们看一个综合示例,展示function如何包装各种类型的可调用对象:
cpp复制#include <iostream>
#include <functional>
#include <string>
// 1. 普通函数
int add(int a, int b) { return a + b; }
// 2. lambda表达式
auto multiply = [](int a, int b) { return a * b; };
// 3. 仿函数(重载了operator()的类)
struct Subtract {
int operator()(int a, int b) const { return a - b; }
};
// 4. 类成员函数
class Calculator {
public:
static int staticAdd(int a, int b) { return a + b; }
int instanceAdd(int a, int b) const { return a + b + offset; }
private:
int offset = 10;
};
int main() {
// 包装普通函数
std::function<int(int, int)> func1 = add;
// 包装lambda
std::function<int(int, int)> func2 = multiply;
// 包装仿函数
Subtract sub;
std::function<int(int, int)> func3 = sub;
// 包装静态成员函数
std::function<int(int, int)> func4 = &Calculator::staticAdd;
// 包装普通成员函数(需要处理this指针)
Calculator calc;
std::function<int(const Calculator&, int, int)> func5 = &Calculator::instanc
