使用+解决lambda的函数指针和std :: function上的模棱两可的重载 [英] Resolving ambiguous overload on function pointer and std::function for a lambda using +

查看:81
本文介绍了使用+解决lambda的函数指针和std :: function上的模棱两可的重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,对foo的第一次调用是含糊的,因此无法编译.

In the following code, the first call to foo is ambiguous, and therefore fails to compile.

第二个,在lambda之前添加了+,以解决函数指针重载.

The second, with the added + before the lambda, resolves to the function pointer overload.

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

+符号在这里做什么?

推荐答案

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

The + in the expression +[](){} is the unary + operator. It is defined as follows in [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不是算术类型等,但是可以转换:

The lambda is not of arithmetic type etc., but it can be converted:

[expr.prim.lambda]/3

[expr.prim.lambda]/3

lambda-expression [...]的类型是唯一的,未命名的非工会类类型-称为 closure type -其属性如下所述

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

[expr.prim.lambda]/6

没有 lambda-capture lambda-expression 的闭包类型具有public non- virtual non- explicit const转换功能指向函数的指针,其参数和返回类型与闭包类型的函数调用运算符相同.此转换函数返回的值应为一个函数的地址,该函数在被调用时与调用闭包类型的函数调用运算符具有相同的作用.

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 (*)().

Therefore, the unary + forces the conversion to the function pointer type, which is for this lambda void (*)(). Therefore, the type of the expression +[](){} is this function pointer type void (*)().

第二个重载void foo(void (*f)())在重载分辨率的排名中成为完全匹配",因此被明确选择(因为第一个重载不是精确匹配").

The second overload void foo(void (*f)()) becomes an Exact Match in the ranking for overload resolution and is therefore chosen unambiguously (as the first overload is NOT an Exact Match).

lambda [](){}可以通过std::function的非显式模板ctor转换为std::function<void()>,该模板可以采用满足CallableCopyConstructible要求的任何类型.

The lambda [](){} can be converted to std::function<void()> via the non-explicit template ctor of std::function, which takes any type that fulfils the Callable and CopyConstructible requirements.

还可以通过闭包类型的转换函数将lambda转换为void (*)()(请参见上文).

The lambda can also be converted to void (*)() via the conversion function of the closure type (see above).

两者都是用户定义的转换序列,并且具有相同的等级.这就是为什么在 first 示例中由于歧义而导致重载解析失败的原因.

Both are user-defined conversion sequences, and of the same rank. That's why overload resolution fails in the first example due to ambiguity.

根据卡西欧·内里(Cassio Neri)的说法,丹尼尔·克鲁格勒(DanielKrügler)的支持下,这种一元+技巧应被指定为行为,即您可以依靠它(请参阅评论中的讨论).

According to Cassio Neri, backed up by an argument by Daniel Krügler, this unary + trick should be specified behaviour, i.e. you can rely on it (see discussion in the comments).

不过,如果您想避免歧义,我建议对函数指针类型使用显式强制转换:您无需询问是什么,以及它为什么起作用;)

Still, I'd recommend using an explicit cast to the function pointer type if you want to avoid the ambiguity: you don't need to ask on SO what is does and why it works ;)

这篇关于使用+解决lambda的函数指针和std :: function上的模棱两可的重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆