大括号或相等的初始值设定在工会
相关:How to initialize a non-POD member in Union大括号或相等的初始值设定在工会
的标准说
在工会的最多一个非静态数据成员可能有大括号或相等的初始值设定。
但
struct Point {
Point() {}
Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;
Point p = Point(1,2);
};
#include <iostream>
int main() {
U u;
std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
}
打印4196960:0
而不是预期的1:2
。
我认为这是一个编译器错误。是这样吗?
C++ 11 [class.ctor]/5的状态:
甲默认构造一类
X
是X
类的构造,可以不使用参数被调用。如果没有用户声明的类X
的构造函数,则不带参数的构造函数将隐式声明为默认值(8.4)。隐式声明的默认构造函数是其类的一个inline public
成员。为X
A类默认缺省的构造被定义为已删除,如果:
X
是具有与非平凡缺省构造的变体构件联合状类,- 任何非静态数据成员,没有撑 - 或等于初始值设定是参考的类型,
- const限定类型(或其阵列)的任何非变异非静态数据成员没有支架 - 或等于初始值设定不具有用户提供的默认构造函数
X
是一个联盟,其所有变体成员都是const限定类型(或其数组),X
是一个非联合类,任何匿名联合成员的所有成员都是const限定类型(或数组物),- 没有支架 - 或等于初始值设定任何直接的或虚拟的基类,或非静态数据成员,具有类类型
M
(或其阵列)和任一M
没有默认的构造或重载解析(13.3)适用于M
的默认构造函数会导致模糊或导致从默认构造函数中删除或无法访问的函数或- 任何直接或虚拟基类或非静态数据成员的类型都具有从默认的默认构造函数中删除或无法访问的析构函数。
一个默认的构造是微不足道的,如果它不是用户提供的,并且如果:
- 其类没有虚拟功能(10.3),并且没有虚基类(10。1),和
- 它的类的没有非静态数据成员具有撑 - 或等于初始值设定,和
- 所有直接基它的类的类具有微不足道的默认构造函数和
- 为其类的所有非静态数据成员都是类类型(或其数组),每个类都有一个简单的默认构造函数。
否则,默认的构造函数是不平凡的。
由于在OP的结构Point
具有非平凡缺省构造,如根据已删除
Point() {}
含有Point
类型的成员的联合一个默认的默认的构造应被定义第一弹:
X
是工会样被形成不良的,其具有与非平凡缺省构造
导致在OP呈现的程序变体成员类。
然而,委员会似乎认为这是的情况下的缺陷,一个联合的成员具有撑 - 或等于初始值设定,每core working group issue 1623:
据12.1 [ class.ctor]段5,
甲默认为类X默认的构造被定义为已删除,如果:
X
是联合般的类,有一个不平凡的默认构造函数的变体成员,...
X
是工会及其所有变种成员是const限定类型(或其阵列)
X
是一种非类联合和任何匿名联合成员的所有成员都是常量限定类型(或其阵列)的,...
是,由于非静态数据成员初始化的存在是一个MEM-初始化的道德等效,这些规则可能应该不修改定义生成的构造时联合成员为已删除有一个非静态数据成员初始值设定项。 (请注意9.5 [class.union]第2-3和7.1.6.1节中的非规范性参考[dcl.type。cv]第2段,如果此限制发生更改,还需要更新。)
将需求添加到需要非静态数据成员初始值设定项或用户的9.5 [class.union]也是有帮助的如果联合的所有成员都有const限定的类型,则提供构造函数。
更为一般的说明,为什么默认的构造函数被定义为仅仅因为成员有一个不平凡的默认构造函数而被删除?联盟本身不知道哪个成员是活动成员,并且默认构造不会初始化任何成员(假设没有支撑或等同初始化器)。由工会的“所有者”来控制活动成员的生命周期(如果有的话),并且要求用户提供的构造函数强制设计模式没有意义。沿着同样的路线,为什么默认的析构函数被定义为仅仅因为成员具有非平凡的析构函数而被删除?如果仅在联合还有用户提供的构造函数时应用,我才会同意这种限制。
发行1623的状态为“提案”,这表明该委员会认为该问题可能是一个缺陷 - 为什么别人允许为工会成员大括号或相等的初始值设定? - 但还没有花时间来确定决议的正确措词。事实上,除了“任何直接或虚拟基类或非静态数据成员”这个字句在任何地方都被替换成了这个字符之外,该段在当前的C++ 14草案N3936([class.ctor]/4)中基本相同更简单“任何潜在构建的子对象”。
虽然两个编译器的行为都不严格符合,但我会认为Clang的行为符合标准的精神。这样看来,GCC变为通过删除默认的构造函数和大括号或相等的初始化程序的组合困惑:
- 它diagnose the program as ill-formed in the absence of the brace-or-equal-initializer,
-
与大括号或相等的初始值设定当前和最大警告GCC 4.8.2不执行工会的初始化所有,并even warns that the members are used uninitialized:
main.cpp: In function 'int main()': main.cpp:17:39: warning: 'u.U::p.Point::y_' is used uninitialized in this function [-Wuninitialized] std::cout << u.p.x_ << ":" << u.p.y_ << std::endl; ^ main.cpp:17:22: warning: 'u.U::p.Point::x_' is used uninitialized in this function [-Wuninitialized] std::cout << u.p.x_ << ":" << u.p.y_ << std::endl; ^
GCC应该可能符合标准并将该程序诊断为不合格,或者模仿叮当的行为,并从括号或等号初始化程序中生成适当的构造函数。
我不希望这样编译,因为联合的默认构造函数应该由于'Point'没有一个简单的默认构造函数而被隐式删除。当然,除非该成员初始化被视为用户提供的默认构造函数。 – chris
cla打印1:2 –
g ++打印134514827:-1218232320 – Veritas