在以下代码中,对 foo
的第一次调用不明确,因此无法编译。
第二个,在 lambda 之前添加 +
,解析为函数指针重载。
#include <functional>
void foo(std::function<void()> f) { f(); }
void foo(void (*f)()) { f(); }
int main ()
{
foo( [](){} ); // ambiguous
foo( +[](){} ); // not ambiguous (calls the function pointer overload)
}
+
符号在这里做什么?
最佳答案
+
在表达式 +[](){}
中是一元 +
运算符(operator)。它的定义如下
[expr.unary.op]/7:
The operand of the unary
+
operator shall have arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument.
lambda 不是算术类型等,但可以转换:
[expr.prim.lambda]/3
The type of the lambda-expression [...] is a unique, unnamed non-union class type — called the closure type — whose properties are described below.
[expr.prim.lambda]/6
The closure type for a lambda-expression with no lambda-capture has a
public
non-virtual
non-explicit
const
conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
因此,一元 +
强制转换为函数指针类型,这是针对此 lambda void (*)()
。因此,表达式 +[](){}
的类型这个函数指针类型是void (*)()
.
第二次过载void foo(void (*f)())
在重载解析的排名中成为精确匹配,因此被明确选择(因为第一个重载不是精确匹配)。
lambda [](){}
可以转换为std::function<void()>
通过std::function
的非显式模板ctor ,它采用满足 Callable
的任何类型和CopyConstructible
要求。
lambda 也可以转换为 void (*)()
通过闭包类型的转换函数(见上文)。
两者都是用户定义的转换序列,并且具有相同的等级。这就是为什么重载解析在第一个示例中由于不明确而失败的原因。
<小时/>根据 Cassio Neri 的说法,并得到 Daniel Krügler 的论证支持,这个一元 +
技巧应该是指定的行为,即您可以依赖它(请参阅评论中的讨论)。
不过,如果您想避免歧义,我建议您使用显式转换为函数指针类型:您不需要询问它的作用和原因;)
关于c++ - 使用 +(一元加)解决 lambda 的函数指针和 std::function 上的不明确重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17822131/