【发布时间】:2014-11-26 01:19:25
【问题描述】:
在 C++11 中,我们可以使用“brace-or-equal-initializer”(标准中的词)进行类内初始化,如下所示:
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 }; 但我个人觉得这很难向几十年来习惯使用= 表单的人解释,因为标准指的是“大括号或 - equal-initializer”,为什么旧的好方法在这种情况下不起作用并不明显。
【问题讨论】:
-
{}初始化语法有点像 hack,它有一堆像这样的奇怪的极端情况 -
我以为你必须使用双括号 - 试试
Foo foo = { { 42 } }; -
@Matt McNabb:与其说
{}是一个黑客,不如说是使用=并希望省略构造是一个黑客,但我个人更喜欢它的符号。无论如何,鉴于 省略是一种优化而不是保证,忽略explicit意味着您冒着额外的意外构造的风险。似乎要求代码明确反映该风险 -Foo foo = Foo{ 42 };- 当构造函数标记为explicit时是合理的。冗长促使人们考虑和简化。虽然很乏味。 -
@TonyD 同意,但您可能对省略号有误。 According to Herb Sutter 省略实际上是有保证的。也就是说,我不知道他是基于什么断言的。
-
@KonradRudolph 嗯。是的,8.5 实际上让我走上了一条糟糕的道路:虽然它暗示(在我看来)
Foo x={a};是复制初始化,但它实际上是 8.5.4 中涵盖的复制列表初始化。并且复制列表初始化与直接列表初始化相同,除非选择了explicit构造函数,否则它将被阻止。与Foo x=a;不同,无论是否在逻辑上都不会创建临时文件。所以this works -- 阻止复制/移动,Foo a={x};样式,编译。没有{}不会编译。
标签: c++ c++11 initializer-list explicit-constructor in-class-initialization