Lambda捕获列表和定义的函数指针类型

时间:2016-07-10 14:50:30

标签: c++ lambda

以下代码无法编译:

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)会编译但是我可以在不更改的情况下执行此操作吗?

2 个答案:

答案 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。