C 使用lambda进行隐式构造函数呼叫期望函数指针

C++ Using lambda for implicit constructor call expecting a function pointer

本文关键字:呼叫 构造函数 期望 函数 指针 使用 lambda      更新时间:2023-10-16

我试图从lambda函数中隐式构造对象。对象的构造函数将功能指针作为参数。但是代码[1]并未与消息编译:

6 : <source>:6:5: note: candidate constructor not viable: no known conversion from '(lambda at /tmp/compiler-explorer-compiler117117-54-dfxyju.lkw98/example.cpp:22:14)' to 'Bar' (aka 'bool (*)()') for 1st argument
    Foo(Bar b) : m_b{b} {}

但标准指出,lambda函数隐式转换为具有相同参数和返回类型[2]的功能指针。这应该在这里适用,因此我希望构造函数可召唤。

那么为什么不编译代码?感谢您的解释!


[1]代码示例:

using Bar = bool(*)();
class Foo
{
public:
    Foo(Bar b) : m_b{b} {}
private:
    Bar m_b;
};
int main()
{   
    // working
    Foo f1 ( [](){ return true; });
    Foo f2 = Bar( [](){ return true; });
    // working implicit conversion
    bool(*tmp)() = []() { return true; };
    Foo f3 = tmp;
    // not working
    Foo f4 = [](){ return true; };
    return 0;
}

https://godbolt.org/g/qe4v1z


[2]第5.1.2节中的C 14标准状态:

没有lambda捕获的lambda表达式的闭合类型具有公共非虚拟非宣传const constrion conversion函数,可指针具有具有相同参数和返回类型的函数,与闭合类型的函数呼叫运算符。此转换函数返回的值应为一个函数的地址,该函数在调用时具有与调用闭合类型的函数调用操作员相同的效果。

这意味着lambda应隐式(非阐释)转换为函数指针。


测试:

  • Clang5.0.0 -Std = C 14
  • msvc14.12/permissive-

是的,它隐式转换为函数指针;这就是bool(*tmp)() = []() { return true; };工作的原因。关键是,在一个隐式转换序列中,只允许使用一个用户定义的转换。

隐式转换序列由以下顺序组成:

  1. 零或一个标准转换序列;
  2. 零或一个用户定义的转换;
  3. 零或一个标准转换序列。

在考虑到构造函数或用户定义的论点时 转换功能,仅允许一个标准转换序列 (否则用户定义的转换可以有效链接)。

对于Foo f4 = [](){ return true; };(即复制初始化),必须通过用户定义的lambda的用户转换函数将lambda转换为函数指针,然后通过Foo的转换构造器转换为Foo,需要两个用户定义的转换,并需要使用两个用户定义的转换。但不允许。

btw:

  1. Foo f1 ( [](){ return true; });起作用,因为对于直接的Intialization,Foo的构造函数将直接调用;lambda转换为函数指针,然后作为参数传递给构造函数,这很好。

  2. Foo f2 = Bar( [](){ return true; });起作用,因为lambda明确转换为功能指针,该指针被隐式转换为 Foo

  3. bool(*tmp)() = []() { return true; }; Foo f3 = tmp;起作用,因为lambda被隐式转换为函数指针为tmp,然后tmp转换为Foo;任何一个隐式转换序列都只需要一个用户定义的转换,然后很好。

  4. Foo f5 = +[](){ return true; };工作是因为operator+导致Lambda转换为函数指针,这意味着对于+[](){ return true; },您将使用类型bool(*)()获得功能指针,然后故事与f2相同。