为什么在直接初始化和赋值时传递lambda而不是复制初始化时编译?

tuk*_*ket 23 c++ lambda initialization variable-assignment c++11

为什么赋值运算符在声明对象的同一行中完成时不允许使用lambda表达式?

它似乎在MSVC中工作.

测试代码:https: //godbolt.org/g/n2Tih1

class Func
{
    typedef void(*func_type)();
    func_type m_f;
public:
    Func() {}
    Func(func_type f) : m_f(f) {}
    Func operator=(func_type f) {
        m_f = f;
        return *this;
    }
};

int main()
{
    // doesn't compile in GCC and clang, it does in MSVC
    Func f1 = []() {

    };

    // compiles!
    Func f2;
    f2 = []() {

    };

    // compiles!
    Func f3([]() {

    });
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 22

Func f1 = []() {};复制初始化,它需要两个用户定义的隐式转换来构造f1,第一个是从lambda到函数指针,第二个是从函数指针到Func.在一个转换序列中只允许一个用户定义的隐式转换,因此它会失败.

(强调我的)

如果T是类类型,并且其他类型的cv-nonqualified版本不是T或从T派生,或者如果T是非类型类型,但是other的类型是类类型,则是用户定义的转换序列可以检查从其他类型转换为T(或从T派生的类型,如果T是类类型并且转换函数可用),并通过重载决策选择最佳的类型.

隐式转换序列按以下顺序包含以下内容:

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

对于f2 = []() {};适当的赋值操作符,尝试调用,Func有一个并且它期望函数指针作为参数; 只需要从lambda到函数指针的一个隐式转换,然后它就可以正常工作.

Func f3([]() {});直接初始化,尝试调用适当的构造函数,Func有一个并且它期望函数指针作为参数.那就像是一样的f2.

您可以从复制初始化和直接初始化之间的区别中获得重点.

此外,复制初始化中的隐式转换必须直接从初始化器生成T,而例如,直接初始化需要从初始化器到T的构造函数的参数的隐式转换.


Fra*_*eux 8

你的第一个案件涉及到两个隐式转换,lambda来void(*)(),然后void(*)()Func.最多可以有1个隐式转换.

如果你可以消除其中一个隐式转换,它应该可以正常工作.以下是您可以尝试的一些潜在解决方案:

// Explicit cast to a function pointer
Func f1 = static_cast<void(*)()>([]() {});

// func_ptr is already a function pointer
//  eliminating one of the implcit conversions
void (*func_ptr)() = [](){};
Func f2 = func_ptr;

// The conversion from `void(*)()` is no longer implicit
Func f3{ [](){} };
Run Code Online (Sandbox Code Playgroud)