当前位置: 首页 > 知识库问答 >
问题:

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

江德润
2023-03-14

在下面的代码中,对< code>foo的第一次调用不明确,因此无法编译。

第二个在lambda前面添加了< code> ,解析为函数指针重载。

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

符号在这里做什么?

共有1个答案

焦驰
2023-03-14

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

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

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

[expr.prim.lambda]/3

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

[expr.prim.lambda]/6

对于没有lambda-捕获的lambda-表达式,闭包类型具有publicnonVirtualnon显式const转换函数,该转换函数指向具有与闭包类型的函数调用操作符相同的参数和返回类型的函数的指针。此转换函数返回的值应为函数的地址,调用该函数时,具有与调用闭包类型的函数调用操作符相同的效果。

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

第二个重载void foo(void(*f)())在重载解决方案的排名中成为Exact Match,因此被明确选择(因为第一个重载不是Exact Match)。

lambda[](){}可以转换为std::function

lambda也可以通过闭包类型的转换函数转换为void(*)()(见上文)。

两者都是用户html" target="_blank">定义的转换序列,并且具有相同的等级。这就是为什么在第一个示例中重载解析由于不明确而失败的原因。

根据卡西奥·内里(Cassio Neri)的说法,在丹尼尔·克鲁格勒(Daniel Krügler)的论点的支持下,这种一元技巧应该是特定的行为,即你可以依靠它(参见评论中的讨论)。

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

 类似资料:
  • > < li> 有什么不同吗? “保存/转移”功能的最佳方式是什么?

  • 请考虑以下代码示例: 我确信它不应该编译,因为编译器不应该能够选择两个构造函数中的一个。g-4.7.3显示了这个预期的行为:它说重载构造函数的调用是不明确的。但是,g-4.8.2成功编译了它。 此代码在 C 11 中是否正确,或者它是此版本 g 的错误/功能?

  • 假设我们有以下简单的代码: 这段代码使用clang编译并打印“T”,但使用gcc我们有以下错误: 我的问题是哪个编译器有bug,gcc还是叮当声?

  • 一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个 指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是 函数指针。 函数指针的定义形式为: returnType (*pointerName)(param list); returnType

  • 我有两个函数的重载,它们采用不同的s,当与的结果一起使用时,会导致后者的歧义问题。我不明白为什么只有这是模棱两可的。 将< code>int()与< code>bind函数一起使用时,我得到一个模糊错误 gcc-5.1错误(类似的还有clang) 然而,以下所有工作 查看构造函数 对我来说,任何在不同的类型上具有多个重载的函数都应该有歧义,但这只是绑定调用的问题。然后我想“也许有一些神奇的事情发生

  • 本文向大家介绍C语言 函数指针(指向函数的指针)详解,包括了C语言 函数指针(指向函数的指针)详解的使用技巧和注意事项,需要的朋友参考一下 一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就