如何在C++中实现类似Java Supplier的未求值表达式传参?
在C++中实现类似Java Supplier的延迟求值功能
Java里的Supplier核心是延迟求值——只有在需要的时候才执行表达式并返回结果。在C++里有几种等价实现方式,各有优劣:
1. 使用std::function(最接近Java Supplier的写法)
std::function<Foo()>是C++的通用可调用对象包装器,和Java的Supplier<Foo>语义几乎一致。调用时用lambda表达式传入延迟执行的逻辑,通过()运算符触发求值。
代码示例
#include <functional> // 假设Foo是已定义的类 class Foo {}; void doSomething(std::function<Foo()> supplier, bool gonnaNeedThatObject) { if (gonnaNeedThatObject) { Foo foo = supplier(); // 在这里处理foo } } int main() { // 传入lambda表达式,仅在supplier()被调用时才执行Foo的构造 doSomething([]() { return Foo(); }, true); return 0; }
优点:类型安全,支持所有可调用对象(lambda、普通函数、成员函数绑定对象等),灵活性拉满。
缺点:基于类型擦除实现,会有轻微的运行时开销。
2. 使用模板参数(极致性能选择)
把可调用对象作为模板参数传入,编译器会在编译期做完全优化,消除任何运行时开销。
代码示例
class Foo {}; template<typename Supplier> void doSomething(Supplier supplier, bool gonnaNeedThatObject) { if (gonnaNeedThatObject) { Foo foo = supplier(); // 处理foo的逻辑 } } int main() { doSomething([]() { return Foo(); }, false); return 0; }
优点:零运行时开销,性能最优,同样支持所有可调用类型。
缺点:不同的可调用对象类型会触发函数的重复实例化,可能增加二进制体积;若为头文件中的模板函数,需注意编译依赖问题。
3. 使用函数指针(仅适用于无状态调用)
如果延迟逻辑不需要捕获外部变量(比如普通函数、无捕获lambda),可以直接用函数指针作为参数,完全没有额外开销。
代码示例
class Foo {}; // 普通函数作为延迟求值逻辑 Foo createFoo() { return Foo(); } void doSomething(Foo(*supplier)(), bool gonnaNeedThatObject) { if (gonnaNeedThatObject) { Foo foo = supplier(); // 处理foo } } int main() { // 传入普通函数指针 doSomething(&createFoo, true); // 无捕获lambda可以隐式转换为函数指针 doSomething([]() { return Foo(); }, false); return 0; }
优点:完全没有运行时开销,语法简单直接。
缺点:只能接受无捕获的可调用对象,无法捕获外部变量,灵活性极差。
方法选择总结
- 优先选
std::function:大多数场景下的平衡之选,灵活性足够,开销可忽略。 - 追求性能选模板参数:适合对性能敏感的底层代码,能接受模板实例化的代价。
- 简单无状态逻辑选函数指针:仅在确定不需要捕获外部变量时使用。
内容的提问来源于stack exchange,提问作者H.v.M.
相关产品推荐
相关产品推荐

