使用 +(一元加)解决 lambda 的函数指针和 std::function 上的不明确重载

问题描述 投票:0回答:1

在下面的代码中,第一次调用

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)
}

这里的

+
符号是做什么用的?

c++ c++11 lambda overloading
1个回答
125
投票

表达式

+
中的
+[](){}
是一元
+
运算符。它的定义如下 [expr.unary.op]/7:

一元

+
运算符的操作数应为算术、无作用域枚举或指针类型,结果为参数的值。

lambda 不是算术类型等,但可以转换:

[expr.prim.lambda]/3

lambda 表达式 [...] 的类型是一种独特的、未命名的非联合类类型 — 称为 闭包类型 — 其属性如下所述。

[expr.prim.lambda]/6

不带

lambda-capturelambda-expression 的闭包类型具有 public

virtual
explicit
 
const
函数指针 的转换函数,具有相同的参数和返回值类型作为闭包类型的函数调用运算符。此转换函数返回的值应是函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果。

因此,一元

+

强制转换为函数指针类型,也就是针对这个lambda
void (*)()
。因此,表达式
+[](){}
的类型就是这个函数指针类型
void (*)()

第二个重载

void foo(void (*f)())

成为重载解析排名中的精确匹配,因此被明确选择(因为第一个重载不是精确匹配)。


lambda

[](){}

 可以通过 
std::function<void()>
 的非显式模板构造函数转换为 
std::function
,它采用满足 
Callable
CopyConstructible
 要求的任何类型。

lambda 还可以通过

闭包类型

 的转换函数转换为 
void (*)()(见上文)。

两者都是用户定义的转换序列,并且具有相同的等级。这就是为什么重载决策在

first 示例中由于不明确而失败的原因。


根据 Cassio Neri 的说法,并得到 Daniel Krügler 的论证支持,这个一元

+

 技巧应该是指定的行为,即你可以依赖它(请参阅评论中的讨论)。

不过,如果您想避免歧义,我建议您使用显式转换为函数指针类型:您不需要询问它的作用和原因;)

© www.soinside.com 2019 - 2024. All rights reserved.