【问题标题】:Why does this compile when passing a lambda in direct initialization and assignment but not with copy initialization?为什么在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?
【发布时间】:2018-11-25 11:17:05
【问题描述】:

为什么赋值运算符不允许在声明对象的同一行中使用 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([]() {

    });
}

【问题讨论】:

  • 试试Func f4 = +[](){}; :-)
  • @Jarod42 太棒了!为什么? o.0
  • 它类似于 François Andrieux 的回答中的static_cast<void(*)()>([]() {})

标签: c++ c++11 lambda initialization variable-assignment


【解决方案1】:

Func f1 = []() {};copy initialization,需要两次用户定义的隐式转换来构造f1,第一个是从lambda到函数指针,第二个是从函数指针到Func。一个conversion sequence中只允许一个用户定义的隐式转换,所以它失败了。

(强调我的)

如果 T 是类类型,并且 other 的类型的 cv 非限定版本不是 T 或派生自 T,或者如果 T 是非类类型,但 other 的类型是类类型,检查可以从 other 的类型转换为 T 的用户定义的转换序列(如果 T 是类类型并且转换函数可用,则转换为从 T 派生的类型) 并通过以下方式选择最佳的转换序列重载决议。

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

1) 零个或一个标准转换序列;
2) 零次或一次用户自定义转换;
3) 零个或一个标准转换序列。

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

Func f3([]() {});direct initialization,尝试调用适当的构造函数,Func 有一个,它期望函数指针作为参数。那么就和f2一样。

你可以从拷贝初始化和直接初始化的区别中理解。

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

【讨论】:

    【解决方案2】:

    您的第一个案例涉及两个隐式转换,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{ [](){} };
    

    【讨论】:

    • 我建议让func_typeFunc 中公开,然后您可以执行Func f1 = static_cast&lt;Func::func_type&gt;([](){});Func::func_type func_ptr = [](){}; 之类的操作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2012-11-07
    相关资源
    最近更新 更多