如何将带捕获的C++柯里化函数传递给函数指针参数?
问题根源
带捕获的lambda无法隐式转换为普通函数指针——函数指针是无状态的,没法存储你捕获的baz变量;只有无捕获的lambda才能自动转成函数指针,这就是你去掉[=]就能编译的原因。
解决方案
方案1:把foo改成模板函数(最推荐)
让foo接受任意可调用对象,不管有没有捕获:
#include <iostream> template<typename Callable> void foo(Callable f) { f(123); // 传入任意long类型参数即可 } auto makeBar(long baz) { return [=](long v) { std::cout << "hello from closure " << baz << ", v=" << v << "\n"; }; } int main() { auto bar = makeBar(2); foo(bar); return 0; }
这种方式没有额外性能开销,而且最灵活,能兼容所有符合调用签名的可调用对象。
方案2:用std::function包装(适合需要类型擦除的场景)
如果foo的参数类型不能是模板(比如需要统一的接口),可以用std::function来容纳带捕获的lambda:
#include <iostream> #include <functional> void foo(std::function<void(long)> f) { f(456); } auto makeBar(long baz) { return [=](long v) { std::cout << "hello from closure " << baz << ", v=" << v << "\n"; }; } int main() { auto bar = makeBar(2); foo(bar); return 0; }
std::function会做类型擦除,带来一点微小的性能开销,但能统一不同可调用对象的类型。
方案3:用全局/静态变量存捕获值(不推荐,仅作特殊场景备选)
如果必须要用普通函数指针(比如要兼容C代码),可以把捕获的baz存在全局或静态变量里,但这种方法线程不安全,多次调用makeBar会覆盖值:
#include <iostream> void foo(void (*)(long v)) {} static long stored_baz; // 静态变量存捕获值 void wrapped_func(long v) { std::cout << "hello from closure " << stored_baz << ", v=" << v << "\n"; } auto makeBar(long baz) { stored_baz = baz; return wrapped_func; } int main() { auto bar = makeBar(2); foo(bar); return 0; }
除非万不得已,否则别用这种方法,很容易引发bug。
内容的提问来源于stack exchange,提问作者DanM
相关产品推荐
相关产品推荐

