Joh*_*nck 18 c++ explicit-constructor initializer-list in-class-initialization c++11
在C++ 11中,我们可以使用"brace-or-equal-initializer"(标准中的单词)进行类内初始化,如下所示:
struct Foo
{
/*explicit*/ Foo(int) {}
};
struct Bar
{
Foo foo = { 42 };
};
Run Code Online (Sandbox Code Playgroud)
但如果我们不发表评论explicit,它就不再编译了.GCC 4.7和4.9说:
error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’
Run Code Online (Sandbox Code Playgroud)
我发现这令人惊讶.C++ 11标准真的是这个代码无法编译的意图吗?
删除它=修复它:Foo foo { 42 };但我个人觉得更难以向那些已经习惯了这种形式的人解释=几十年,而且由于标准指的是"支撑或平等初始化器",因此很好的旧方式在这种情况下不起作用.
小智 12
我不能解释这背后的基本原理,但我可以重复这个显而易见的事实.
我发现这令人惊讶.C++ 11标准真的是这个代码无法编译的意图吗?
§13.3.1.7
在copy-list-initialization中,如果选择了显式构造函数,则初始化是错误的.
删除=修复它:
Foo foo { 42 };但是我个人觉得更难以向那些习惯于使用=几十年的形式的人解释,并且因为标准指的是"支撑或平等初始化器",所以为什么好的不明显旧方法在这种情况下不起作用.
Foo foo { 42 }是直接初始化,而等号(带大括号)使它成为复制列表初始化.另一个答案是因为编译因复制初始化而失败(没有大括号的等号),因此复制列表初始化失败也不足为奇,但两者因各种原因而失败.
cppreference:
直接初始化比复制初始化更宽松:复制初始化仅考虑非显式构造函数和用户定义的转换函数,而直接初始化则考虑所有构造函数和隐式转换序列.
他们在显式说明符上的页面:
指定构造函数和(自C++ 11以来)转换运算符,它们不允许隐式转换或复制初始化.
另一方面,对于copy-list-initialization:
T object = { arg1,arg2,... }; (10)
10)在等号的右侧(类似于复制初始化)
否则,T的构造函数分为两个阶段:
- 如果前一个阶段没有产生匹配,则T的所有构造函数都参与对由braced-init-list元素组成的参数集的重载解析,并限制只允许非缩小转换.如果此阶段产生显式构造函数作为复制列表初始化的最佳匹配,则编译失败(注意,在简单的复制初始化中,根本不考虑显式构造函数)
正如在copy-list-initialization允许显式构造函数允许的情况下所讨论的那样?,编译失败,因为选择了显式构造函数但不允许使用.
Ant*_*vin 12
如果Foo(int)是explicit,那么这也不会编译:
Foo foo = 42;
Run Code Online (Sandbox Code Playgroud)
因此,对于"已经习惯=了几十年的形式"的人来说,表单{}也不会编译也就不足为奇了.
小智 7
小部件w = {x};
这称为"复制列表初始化".它与小部件w {x}相同; 除了不能使用显式构造函数.保证只调用一个构造函数.
来自http://herbsutter.com/2013/05/09/gotw-1-solution/
有关可以初始化对象的各种方法的详细讨论,请参阅本文的其余部分.