为啥在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?
Posted
技术标签:
【中文标题】为啥在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?【英文标题】: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(*)()>([]() )
。
哦,我明白了:***.com/questions/18889028/…
【参考方案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_type
在Func
中公开,然后您可以执行Func f1 = static_cast<Func::func_type>([]());
和Func::func_type func_ptr = []();
之类的操作以上是关于为啥在直接初始化和赋值中传递 lambda 而不是复制初始化时会编译?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Python 的 `lambda` 表达式中不允许赋值?