C++stdfunction
外观
C++ std::function[编辑 | 编辑源代码]
std::function 是C++11标准库中引入的通用函数包装器,属于<functional>
头文件。它提供了一种类型安全的方式存储、复制和调用任何可调用对象(函数、lambda表达式、函数对象、绑定表达式等)。
基本概念[编辑 | 编辑源代码]
std::function的核心特性:
- 可以存储任何可调用目标(Callable Target),只要其签名与function的模板参数匹配
- 提供统一的调用接口
operator()
- 当不含可调用目标时,调用会抛出
std::bad_function_call
异常 - 是多态函数包装器,运行时动态绑定具体实现
数学上可以表示为函数类型的包装器,其中A是参数类型,B是返回类型。
声明语法[编辑 | 编辑源代码]
基本声明格式:
#include <functional>
std::function<return_type(parameter_types)> func_name;
示例声明:
std::function<int(int, int)> binary_op; // 包装返回int,接受两个int参数的函数
std::function<void()> callback; // 包装无参数无返回的函数
基础用法示例[编辑 | 编辑源代码]
包装普通函数[编辑 | 编辑源代码]
#include <iostream>
#include <functional>
int add(int a, int b) {
return a + b;
}
int main() {
std::function<int(int, int)> func = add;
std::cout << "Result: " << func(3, 4) << std::endl; // 输出: Result: 7
return 0;
}
包装Lambda表达式[编辑 | 编辑源代码]
#include <iostream>
#include <functional>
int main() {
std::function<int(int)> square = [](int x) { return x * x; };
std::cout << "Square of 5: " << square(5) << std::endl; // 输出: Square of 5: 25
return 0;
}
包装函数对象[编辑 | 编辑源代码]
#include <iostream>
#include <functional>
struct Multiply {
int operator()(int a, int b) const {
return a * b;
}
};
int main() {
std::function<int(int, int)> func = Multiply();
std::cout << "Product: " << func(3, 4) << std::endl; // 输出: Product: 12
return 0;
}
成员函数处理[编辑 | 编辑源代码]
包装成员函数需要结合std::bind
或lambda表达式:
#include <iostream>
#include <functional>
class MyClass {
public:
int memberFunc(int x) {
return x * 2;
}
};
int main() {
MyClass obj;
// 使用std::bind
std::function<int(int)> func1 = std::bind(&MyClass::memberFunc, &obj, std::placeholders::_1);
// 使用lambda
std::function<int(int)> func2 = [&obj](int x) { return obj.memberFunc(x); };
std::cout << func1(5) << ", " << func2(5) << std::endl; // 输出: 10, 10
return 0;
}
状态检查[编辑 | 编辑源代码]
使用operator bool()
检查是否包含有效目标:
#include <iostream>
#include <functional>
void checkFunction(const std::function<void()>& func) {
if (func) {
std::cout << "Function is callable" << std::endl;
func();
} else {
std::cout << "Function is empty" << std::endl;
}
}
int main() {
std::function<void()> emptyFunc;
checkFunction(emptyFunc); // 输出: Function is empty
emptyFunc = []{ std::cout << "Hello!" << std::endl; };
checkFunction(emptyFunc); // 输出: Function is callable 然后输出: Hello!
return 0;
}
性能考虑[编辑 | 编辑源代码]
std::function的实现通常使用类型擦除(Type Erasure)技术,这会带来一定的性能开销:
与直接函数调用相比,std::function的调用大约有2-3倍的性能下降。在性能关键路径上应考虑直接使用模板或函数指针。
实际应用案例[编辑 | 编辑源代码]
回调机制[编辑 | 编辑源代码]
在事件驱动系统中广泛使用:
#include <iostream>
#include <functional>
#include <vector>
class Button {
std::function<void()> onClick;
public:
void setOnClick(const std::function<void()>& callback) {
onClick = callback;
}
void click() {
if (onClick) onClick();
}
};
int main() {
Button btn;
btn.setOnClick([]() {
std::cout << "Button clicked!" << std::endl;
});
btn.click(); // 输出: Button clicked!
return 0;
}
策略模式实现[编辑 | 编辑源代码]
运行时替换算法策略:
#include <iostream>
#include <functional>
#include <vector>
class Sorter {
std::function<void(std::vector<int>&)> strategy;
public:
void setStrategy(const std::function<void(std::vector<int>&)>& s) {
strategy = s;
}
void sort(std::vector<int>& data) {
if (strategy) strategy(data);
}
};
int main() {
Sorter sorter;
std::vector<int> data = {5, 2, 8, 1, 9};
// 设置冒泡排序策略
sorter.setStrategy([](std::vector<int>& v) {
for (size_t i = 0; i < v.size(); ++i)
for (size_t j = 0; j < v.size()-i-1; ++j)
if (v[j] > v[j+1]) std::swap(v[j], v[j+1]);
});
sorter.sort(data);
for (int n : data) std::cout << n << " "; // 输出: 1 2 5 8 9
return 0;
}
与函数指针比较[编辑 | 编辑源代码]
特性 | std::function | 函数指针 |
---|---|---|
可调用类型 | 任何可调用对象 | 仅普通函数 |
捕获状态 | 可以 | 不可以 |
类型安全 | 是 | 是 |
性能 | 较低 | 较高 |
灵活性 | 高 | 低 |
常见问题[编辑 | 编辑源代码]
为什么使用std::function而不是auto?[编辑 | 编辑源代码]
auto
在编译时确定类型,无法存储在容器中或作为类成员- std::function提供统一的类型接口,便于传递和存储
如何传递带捕获的lambda?[编辑 | 编辑源代码]
直接赋值即可,std::function会自动处理捕获状态:
int x = 10;
std::function<int()> func = [x]() { return x * 2; };
总结[编辑 | 编辑源代码]
std::function是C++中强大的函数包装器,它:
- 提供统一的调用接口
- 支持多种可调用对象
- 实现类型安全的回调机制
- 在需要运行时多态性的场景特别有用
页面模块:Message box/ambox.css没有内容。
不要滥用std::function,在编译时能确定类型的场景应优先使用模板或auto。 |
扩展阅读[编辑 | 编辑源代码]
- C++标准库文档:std::function
- 类型擦除技术
- 函数式编程概念