std::function:类型擦除的可调用对象
通过 std::function 擦除类型,并理解小型缓冲区优化
std::function:类型擦除的可调用对象 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
问题:一种类型容纳多种可调用对象
每个 Lambda 表达式都有唯一类型。每个函数指针也有不同的类型。我们需要一种能够容纳它们的统一类型——std::function。
模板参数
std::function<Signature> 接受返回类型和参数类型。只要签名匹配,它就能接受任何可调用对象。
#include <functional>
std::function<int(int, int)> op;
op = [](int a, int b) { return a + b; };
std::cout << op(3, 4); // 7存储不同的可调用对象
同一个 std::function 变量可以存储 Lambda 表达式、函数指针或函子,只要签名匹配即可。
std::function<int(int)> f;
f = [](int x) { return x * 2; }; // lambda
f = ::abs; // function pointer
f = std::negate<int>{}; // functor类型擦除
在内部,std::function 使用类型擦除:它可以存储任何可调用对象,并通过统一接口隐藏其真实类型。通常还会进行一次小型堆分配。
性能代价
通过 std::function 调用时会涉及间接调用(类似于虚函数)。这比直接调用 Lambda 表达式更慢。请避免在性能关键路径中使用。
何时使用 std::function
在以下情况下可以使用它:
- 将回调存储在容器或类成员中
- 从函数返回可调用对象
- 构建插件或事件系统
空的 std::function
默认构造的 std::function 是空的。调用它会抛出 std::bad_function_call。
std::function<void()> f;
if (f) f(); else std::cout << "no callback set";成员函数指针
请使用 std::bind 绑定成员函数,或者将其包装在 Lambda 表达式中。
struct Obj { void greet(int) {} };
Obj o;
std::function<void(int)> cb = [&](int n) { o.greet(n); };与函数指针比较
函数指针无法存储状态。std::function 可以,但代价是进行间接调用。
与模板比较
带有可调用对象参数的模板会在编译期进行特化,速度最快。std::function 在运行时解析,速度较慢但更加灵活。
template <typename F>
void run(F f) { f(); } // compile-time, no overhead
void run(std::function<void()> f) { f(); } // runtime, type erasureC++23 中的 std::function:std::function_ref
C++23 增加了 std::function_ref,它是可调用对象的非拥有型视图。当生命周期有明确边界时,它可以避免堆分配。
替代方案
还有一些轻量级替代方案:std::move_only_function(C++23)、tl::function_ref 和 folly::Function。请根据需求进行选择。
快速检查
std::function 的主要缺点是什么?
总结
std::function<Signature> 可以存储任何签名匹配的可调用对象。它适用于回调、插件以及可调用对象的运行时多态,但代价是进行间接调用。
常见问题解答
「std::function:类型擦除的可调用对象」课时是免费的吗?
是的 — 「std::function:类型擦除的可调用对象」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「std::function:类型擦除的可调用对象」这节课中我会学到什么?
通过 std::function 擦除类型,并理解小型缓冲区优化 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「std::function:类型擦除的可调用对象」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 函数对象与仿函数
- Lambda 按值、按引用捕获与 mutable
- 泛型 Lambda 与闭包(C++14)
- std::function:类型擦除的可调用对象