C++11:使用 "= {}" 的类内初始化不适用于显式构造函数
C++11: in-class initializaton with "= {}" doesn't work with explicit constructor
在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 };
,但我个人发现这很难向几十年来习惯使用=
的人解释,而且由于该标准指的是"大括号或相等的初始值设定项",所以不清楚为什么旧的好方法在这种情况下不起作用。
我无法解释这背后的原理,但我可以重复显而易见的内容。
我觉得这很奇怪。这真的是C++11的意图吗这个代码不编译的标准?
§13.3.1.7
在副本列表初始化中,如果选择了显式构造函数,则初始化格式不正确。
删除=修复了它:
Foo foo { 42 };
,但我个人发现更难向那些习惯了用=for的形式的人解释几十年,并且由于该标准指的是"brace or equal initializer"不清楚为什么采用旧的好方法在这种情况下不起作用。
Foo foo { 42 }
是直接初始化,而等号(带大括号)使其成为复制列表初始化。另一个答案是,因为编译在副本初始化时失败(没有大括号的等号),所以它在副本列表初始化时也失败也就不足为奇了,但两者失败的原因不同。
cppreference:
直接初始化比复制初始化更宽松:复制初始化只考虑非显式构造函数和用户定义的转换函数,同时直接初始化考虑所有构造函数和隐式转换序列。
他们在明确的说明符上的页面:
指定构造函数和(自C++11以来)转换不允许隐式转换的运算符或复制初始化。
另一方面,对于复制列表初始化:
T对象={arg1、arg2,…};(10)
10) 在等号的右侧(类似于复制初始化)
否则,在两个阶段中考虑T的构造函数:
- 如果前一阶段没有产生匹配,则T的所有构造函数都会参与针对以下参数集的重载解析由支撑的init列表的元素组成,具有限制只允许非窄化转换如果这个阶段生成一个显式构造函数作为复制列表初始化,编译失败(注意,简单复制初始化,完全不考虑显式构造函数)
正如在"如果复制列表初始化允许显式构造函数,会出现什么问题?"中所讨论的那样?,编译失败,因为选择了显式构造函数,但不允许使用该构造函数。
如果Foo(int)
是explicit
,那么它也不会编译:
Foo foo = 42;
因此,对于"几十年来一直习惯使用=
的表单的人"来说,使用{}
的表单也不会编译也就不足为奇了。
小部件w={x}
这被称为"复制列表初始化"。它的含义与小部件w{x}相同;除了不能使用显式构造函数之外。可以保证只调用一个构造函数。
发件人http://herbsutter.com/2013/05/09/gotw-1-solution/
有关初始化对象的各种方法的详细讨论,请参阅本文的其余部分。
- 为什么我的 c++ 程序检查不是初始化的变量?
- "变量":函数中函数作用域不允许初始化的自动或寄存器变量'naked'
- 为什么std::atomic的默认构造函数不默认初始化底层存储值
- 数组不保存初始化值
- 为什么作为返回类型的右值引用不能初始化非常量引用?
- 程序告诉我初始化在编写简单的C ++代码时不需要初始化的变量
- IMFSinkWriter::BeginWriting 不会初始化,因为 IMFMediaEventGenerator
- OpenGL C++:VBO 的结构包装器不会初始化成员
- Visual Studio,找不到初始化术语,无法再调试
- C 错误变量大小对象可能不会初始化
- 为什么可以将Char指针变量初始化为字符串,而INT指针变量不能初始化到整数数组
- 使用C 中的Cython CDEF公共变量:变量永远不会初始化
- 为什么您可以初始化常量引用,但不能初始化来自右值的非常量引用
- 为什么我的变量被强制初始化为 0,即使它不应该初始化?
- C++将数组直接传递到函数中,而不首先初始化它
- 为什么在构造函数之外不允许初始化类成员
- 全局静态常量字符串不会初始化
- 为什么VS2013不零初始化此结构?
- auto_ptr构造函数主体(不在初始化器列表中)的成员初始化
- C++ 为什么我可以初始化静态常量字符,但不能初始化类定义中的静态常量双精度