该+
表达式中的+[](){}
是一元+
运算符。在[expr.unary.op] / 7中定义如下:
一元运算+
符的操作数应具有算术,无作用域枚举或指针类型,并且结果是自变量的值。
lambda不是算术类型等,但是可以将其转换为:
[expr.prim.lambda] / 3
lambda表达式的类型是唯一的,未命名的非工会类类型(称为闭包类型),其属性如下所述。
[expr.prim.lambda] / 6
用于闭合型λ-表达无λ-捕获具有public
非virtual
非explicit
const
转换功能指针函数具有相同的参数和返回类型为闭合类型的函数调用操作。该转换函数返回的值应是一个函数的地址,该地址在被调用时与调用闭包类型的函数调用操作符具有相同的作用。
因此,一元+
强制转换为该lambda的函数指针类型void (*)()
。因此,表达式的类型+[](){}
就是该函数指针类型void (*)()
。
第二个过载void foo(void (*f)())
在过载解决方案的排名中成为“精确匹配”,因此可以明确选择(因为第一个过载不是“精确匹配”)。
[](){}
可以std::function<void()>
通过的非显式模板ctor 将lambda 转换为,该模板std::function
可以采用满足Callable
和CopyConstructible
要求的任何类型。
lambda也可以void (*)()
通过闭包类型的转换函数转换为(见上文)。
两者都是用户定义的转换序列,并且具有相同的等级。这就是第一个示例中由于歧义而导致重载解析失败的原因。
根据卡西欧·内里(Cassio Neri)的支持,丹尼尔·克鲁格勒(DanielKrügler)的论点支持了这一一元+
技巧,应该将其指定为行为,即您可以依靠它(请参阅评论中的讨论)。
尽管如此,如果您想避免歧义,我还是建议对函数指针类型使用显式转换:您无需询问SO的作用和作用;)
std::bind
到std::function
对象,该对象可以类似于函数左值调用。