在C++11中,我们可以使用“大括号或等号初始化器”(标准中的措辞)进行类内初始化,如下所示:
在C++11中,我们可以使用“大括号或等号初始化器”(标准中的措辞)进行类内初始化,如下所示:
struct Foo
{
/*explicit*/ Foo(int) {}
};
struct Bar
{
Foo foo = { 42 };
};
但是如果我们取消注释explicit
,它将无法编译。GCC 4.7和4.9会显示以下错误信息:
error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’
我觉得这很令人惊讶。C++11标准真的是要这段代码无法编译吗?
删除等号=
即可解决:Foo foo { 42 };
但我个人觉得这种方式更难向习惯于使用带有等号=
的人解释,而且由于标准引用到了“大括号或等号初始化”,所以为什么传统的方式在这种情况下行不通并不明显。
{}
初始化器语法有点像是一种 hack,而且它还有很多奇怪的边界情况,比如这个。 - M.MFoo foo = { { 42 } };
- Carl Burnett{}
本身就是一个hack,而是使用=
并希望出现省略构造的方式才是一个hack,但我个人更喜欢这种写法。无论如何,由于省略构造只是一种优化而非保证,忽略explicit
会导致额外的意外构造。因此,当构造函数标记为explicit
时,要求代码显式反映这种风险 -Foo foo = Foo{ 42 };
是合理的。这种冗长的写法促使人们思考和简化,虽然有些繁琐。 - Tony DelroyFoo x={a};
是复制初始化,但实际上它是8.5.4中涵盖的复制列表初始化。而且,复制列表初始化与直接列表初始化相同,除非选择了一个“显式”的构造函数,否则会被阻止。与Foo x=a;
不同,没有逻辑或者不合适的临时变量被创建。因此,这个可以工作 -- 被阻止的复制/移动,Foo a={x};
样式,编译通过。如果没有{}
将不能编译。 - Yakk - Adam Nevraumont