繁体   English   中英

包含常量成员的POD结构

[英]POD structs containing constant member

使用此代码:

struct A
{
    int i;
    const int b;
};

// The union is to verify that A is a type that can be used in a union.
union U
{
    A a;
    int b;
};

int main()
{
    U a = {1, 1};
    U b = {2, 1};
}

g ++版本4.8.3抱怨错误:

a.cpp:9:4: error: member ‘A U::a’ with copy assignment operator not allowed in union
  A a;
    ^
a.cpp:9:4: note: unrestricted unions only available with -std=c++11 or -std=gnu++11

但是clang 3.5.0编译这段代码没有错误。 哪一个是正确的? 这是编译器错误吗?

我试图解决这个问题:

从C ++ 03标准第9.5节第1段:

在联合中,最多一个数据成员可以在任何时间处于活动状态,也就是说,最多一个数据成员的值可以随时存储在并集中。 [注意:为了简化联合的使用,我们做了一个特别的保证:如果一个POD-union包含几个共享一个公共初始序列的POD结构(9.2),并且这个POD-union类型的一个对象包含一个在POD结构中,允许检查任何POD结构成员的共同初始序列; 见9.2。 ] union的大小足以包含其最大的数据成员。 每个数据成员都被分配,就好像它是结构的唯一成员一样。 联合可以具有成员函数(包括构造函数和析构函数),但不具有虚函数(10.3)。 工会不得有基类。 联合不得用作基类。 具有非平凡构造函数(12.1),非平凡复制构造函数(12.8),非平凡析构函数(12.4)或非平凡复制赋值运算符(13.5.3,12.8)的类的对象不能是一个联盟的成员,也不是一系列这样的对象 如果联合包含静态数据成员或引用类型的成员,则该程序格式错误。

从C ++ 03标准部分12.8第10和11段:

如果类定义未显式声明复制赋值运算符,则会隐式声明一个。 如果X& X::operator=(const X&)每个直接基类B都有一个复制赋值运算符,其参数类型为const B&,const volatile B&or,则类X的隐式声明的复制赋值运算符将具有X& X::operator=(const X&)形式。 B,对于类型为M(或其数组)的X的所有非静态数据成员,每个这样的类类型都有一个复制赋值运算符,其参数类型为const M&,const volatile M&or M.

Otherwise, the implicitly declared copy assignment operator will have the form X& X::operator=(X&) ...

如果隐式声明类X并且类X没有虚函数(10.3)且没有虚基类(10.1),并且X的每个直接基类都有一个普通的复制赋值运算符,则类X的复制赋值运算符是微不足道的。 X的所有非静态数据成员都是类类型(或其数组),每个这样的类类型都有一个普通的复制赋值运算符 ; 否则复制赋值运算符是非常重要的。

我不确定哪个编译器是正确的,因为我不知道常量成员是否有一个简单的复制赋值运算符。

编辑:编译命令是:

clang++ a.cpp -o a
g++ a.cpp -o a

Edit2:为了表明g ++不抱怨A :: b是const但是A没有构造函数,我也试过这个程序:

struct A
{
    int i;
    const int b;
};

int main()
{
    A a = {1, 1};
}

这在g ++和clang ++上编译时没有错误:

g++ b.cpp -o b
clang++ b.cpp -o b

正如您所正确指出的那样,复制赋值运算符是隐式声明的并且是微不足道的。 默认构造函数也是如此,它也是微不足道和隐式声明的。

请注意,这两个成员函数都没有隐式定义 - 只有在使用它们时才会发生,[class.ctor] / 7:

当用于创建类类型(1.8)的对象时,将隐式定义类的隐式声明的默认构造函数。

..这显然不是这种情况。
这是关键的区别,以及@ dasblinkenlight的引用与此事无关的原因:默认构造函数从未定义,因此缺少mem-initializer-id的段落不适用。

那么const成员和赋值运算符是如何连接的? 这里:

当为其类类型的对象分配其类类型的值或从其类类型派生的类类型的值时,将 隐式定义隐式声明的复制赋值运算符 如果隐式定义了复制赋值运算符的类具有以下内容,则程序格式不正确:

  • const类型的非静态数据成员 ,或[..]

因此,如果使用复制赋值运算符,程序将是错误的。 但事实并非如此。 所有特殊成员函数都是单独声明的,对非静态数据成员的const -ness的任何限制仅适用于隐式定义的特殊成员函数。

举个例子,拿

struct A
{
    int i;
    const int b;
};

int main()
{
    A a = {1, 1};
}

在GCC下编译得很好 你的计划也应该是格式良好的,因为所有关于工会成员特殊成员职能的要求都由A来满足。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM