使用+(一元加号)解决lambda的函数指针和std::function上的多义性重载 [英] Resolving ambiguous overload on function pointer and std::function for a lambda using + (unary plus)

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

问题描述

在下面的代码中,对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)
}

+符号在这里做什么?

推荐答案

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

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

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

[expr.prim.lambda]/3

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

[expr.prim.lambda]/6

lambda-expression没有lambda-capture的闭包类型有一个publicvirtualconst转换函数,该函数指向与闭包类型的函数调用运算符具有相同参数和返回类型的函数指针。此转换函数返回的值应为调用时与调用闭包类型的函数调用运算符具有相同效果的函数的地址。

因此,一元+强制转换为函数指针类型,该类型适用于这个lambdavoid (*)()。因此,表达式+[](){}的类型是该函数指针类型void (*)()

第二个重载void foo(void (*f)())在重载解析排名中变为完全匹配,因此被毫不含糊地选择(因为第一个重载不是完全匹配)。


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

也可以通过闭包类型的转换函数将lambda转换为void (*)()(如上所述)。

两者都是用户定义的转换序列,且具有相同的等级。这就是第一个示例中重载解析由于多义性而失败的原因。


根据Cassio Neri的说法,并得到Daniel Krügler的支持,这个一元的+技巧应该是指定的行为,也就是说,您可以依赖它(参见评论中的讨论)。

不过,如果您想避免歧义,我建议您使用显式转换到函数指针类型:您不需要问它做了什么,为什么它会工作;)

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

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