以下代码无法编译:
typedef void(*RunnableFun)(int); //pointer-to-function type
void foo(RunnableFun f) {
}
void bar(const std::string& a) {
foo([&](int) -> void { std::cout << a; });
}
和IntelliSense告诉我
no suitable conversion function from "lambda []void (int)->void" to "RunnableFun" exists
并且编译器正在抱怨
'void foo(RunnableFun)' : cannot convert argument 1 from 'bar::<lambda_796873cf40a6be4e411eb9df14f486bf>' to 'RunnableFun'
但以下编译:
typedef void(*RunnableFun)(int); //pointer-to-function type
void foo(RunnableFun f) {
}
void bar(const std::string&) {
// Notice the empty capture list
foo([](int) -> void { std::cout << "dummy"; });
}
如何保留foo()
的签名,但是在第一个代码示例中实现我尝试过的内容?
P.S。:将foo的签名更改为void foo(std::function<void(int)> f)
会编译但是我可以在不更改的情况下执行此操作吗?
答案 0 :(得分:7)
您可以查看大部分standard library algorithm functions。当他们采用&#34;谓词&#34; (可调用对象)他们将它作为模板参数。
所以你可以把你的功能作为模板:
template<typename FunctionType>
void foo(FunctionType f) {
}
无需进行其他更改。
无论是这个还是使用std::function
,您都无法在不更改foo
功能的情况下解决问题。
答案 1 :(得分:2)
指向函数的指针仅存储执行位置,它不存储其他状态。执行之间的唯一变化必须由全球状态确定。
在您的情况下,您希望lambda捕获本地状态。因此,在a="hello"
之后调用时,它打印的值不同于a="world"
之后调用的值。
简短的回答是&#34;太糟糕了,太伤心了,但没有&#34;。
你可以破解一下。您可以将a
存储在lambda中的static std::string ga;
和accessmit中。请注意,这是丑陋的,不是可重入的,会不必要地将代码暴露给全局状态,并且通常是一个坏主意。
void bar(const std::string& a) {
static std::string ga;
ga = a; // note, separate line
foo([](int) -> void { std::cout << ga; });
}
通常纯函数指针回调API是设计API的无知傻瓜的标志:正确的C风格回调需要void*
,正确的C ++回调是std::function
或模板可调用或类似。 (无知,因为他们不知道void*
模式是常见的:傻瓜,因为即使你不知道它,他们在尝试他们的系统几次之后也没有自己解决这个问题,并注意到了一个巨大的漏洞。没关系:大多数程序员都是傻瓜,直到他们自己犯了 all 错误!)
如果实际有一个void*
或等效的参数,你会被回复,你在问题中省略了它,答案完全不同。只需在void*
中存储一个ptr-to-lambda,并存储一个无状态lambda,它从void*
转换并调用有状态lambda。