C++ 并集中的大括号或等号初始值设定项

C++ 并集中的大括号或等号初始值设定项,c++,c++11,g++,compiler-bug,C++,C++11,G++,Compiler Bug,相关的: 标准上说 一个联合的最多一个非静态数据成员可以有一个大括号或相等的初始值设定项 但是 结构点{ 点(){} 点(intx,inty):x_ux,y_y{} int x_uux,y_uux; }; 联合大学{ intz; 双w; 点p=点(1,2); }; #包括 int main(){ U U; std::coutC++11[class.ctor]/5状态: 类X的默认构造函数是类X的构造函数,可以不带参数调用。如果类X没有用户声明的构造函数,则没有参数的构造函数隐式声明为默认构造函数

相关的:

标准上说

一个联合的最多一个非静态数据成员可以有一个大括号或相等的初始值设定项

但是

结构点{
点(){}
点(intx,inty):x_ux,y_y{}
int x_uux,y_uux;
};
联合大学{
intz;
双w;
点p=点(1,2);
};
#包括
int main(){
U U;

std::coutC++11[class.ctor]/5状态:

X
的默认构造函数是类
X
的构造函数,可以不带参数调用。如果类
X
没有用户声明的构造函数,则没有参数的构造函数隐式声明为默认构造函数(8.4)。隐式声明的默认构造函数是其类的
内联public
成员。如果满足以下条件,则类
X
的默认构造函数定义为已删除:

  • X
    是一个类似于union的类,它有一个带有非平凡默认构造函数的变量成员
  • 没有大括号或相等初始值设定项的任何非静态数据成员都是引用类型
  • 没有大括号或相等初始值设定项的const限定类型(或其数组)的任何非变量非静态数据成员没有用户提供的默认构造函数
  • X
    是一个并集,其所有变体成员都是常量限定类型(或其数组)
  • X
    是一个非联合类,任何匿名联合成员的所有成员都是常量限定类型(或其数组)
  • 任何直接或虚拟基类,或没有大括号或相等初始值设定项的非静态数据成员,都具有类类型
    M
    (或其数组),并且
    M
    都没有默认构造函数或重载解析(13.3)当应用于
    M
    的默认构造函数时,会导致歧义或从默认构造函数中删除或无法访问的函数,或
  • 任何直接或虚拟基类或非静态数据成员的类型都具有析构函数,该析构函数可从默认构造函数中删除或无法访问
如果默认构造函数不是用户提供的,并且:

  • 它的类没有虚拟函数(10.3)和虚拟基类(10.1),并且
  • 其类的任何非静态数据成员都没有大括号或相等的初始值设定项,并且
  • 它的类的所有直接基类都有普通的默认构造函数,并且
  • 对于其类的所有类类型(或其数组)的非静态数据成员,每个此类类都有一个简单的默认构造函数
否则,默认构造函数是非常重要的

由于OP中的struct
有一个非常重要的默认构造函数

Point() {}
根据第一个项目符号,包含
Point
类型成员的联合的默认构造函数应定义为已删除:

  • X
    是一个类似于union的类,它有一个带有非平凡默认构造函数的变量成员
导致OP中呈现的程序格式错误

然而,委员会似乎认为这是一个联盟成员有支架或相等的初始化器的缺点,即:

根据第12.1款【类别C】第5段

在以下情况下,类X的默认构造函数被定义为已删除:

  • X
    是一个类似于union的类,它有一个带有非平凡默认构造函数的变量成员

  • Point() {}
    
  • X
    是一个并集,其所有变体成员都是常量限定类型(或其数组)

  • X
    是一个非联合类,任何匿名联合成员的所有成员都是常量限定类型(或其数组)

由于非静态数据成员初始值设定项的存在在道德上等同于mem初始值设定项,因此可能应对这些规则进行修改,以便在联合成员具有非静态数据成员初始值设定项时,不将生成的构造函数定义为删除。(请注意9.5[class.union]第2-3和7.1.6.1段中的非规范性引用。)[dcl.type.cv]第2段,如果此限制发生变化,也需要更新。)

如果9.5[class.union]中的所有成员都具有const限定类型,则需要非静态数据成员初始值设定项或用户提供的构造函数,这也会很有帮助

更一般地说,为什么仅仅因为一个成员有一个非平凡的默认构造函数,默认构造函数就被定义为deleted?联合本身不知道哪个成员是活动的,默认构造不会初始化任何成员(假设没有大括号或相等的初始值设定项)。这取决于“所有者”用于控制活动成员的生存期的联合(如果有),并且要求用户提供构造函数是在强制一个没有意义的设计模式。同样,为什么仅仅因为一个成员有一个非平凡的析构函数,就将默认析构函数定义为deleted?我同意这个限制,如果它只适用于union也有一个用户提供的构造函数

第1623期的状态为“起草”,这表明委员会认为这一问题可能是一个缺陷——否则为什么允许工会成员使用括号或同等的初始值?——但尚未花时间确定决议的正确措辞。事实上,该段在当前的C++14草案N3936([class.ctor]/4) ,除了“任何直接或虚拟基类或非静态数据成员”这一措辞被更简单的“任何可能构造的子对象”所取代

虽然两个编译器的行为并不严格一致,但我认为Clang的行为符合标准的精神。
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;
                      ^