首页 文章

包含常量成员的POD结构

提问于
浏览
11

使用此代码:

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编译这段代码没有错误 . 哪一个是正确的?这是编译器错误吗?

My attempt at solving this:

从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的每个直接基类B都有一个复制赋值运算符,其参数类型为const B&,const volatile B&or,则类X的隐式声明的复制赋值运算符将具有X&X :: operator =(const X&)形式 . B,对于类型为M(或其数组)的X的所有非静态数据成员,每个这样的类类型都有一个复制赋值运算符,其参数类型为const M&,const volatile M&或M.否则,隐式声明的复制赋值运算符将具有X&X :: operator =(X&)形式...如果隐式声明并且类X没有虚函数(10.3)且没有虚拟基础,则类X的复制赋值运算符是微不足道的类(10.1),并且X的每个直接基类具有普通的复制赋值运算符,并且对于类类型(或其数组)的X的所有非静态数据成员,每个这样的类类型具有普通的复制赋值运算符;否则复制赋值运算符是非常重要的 .

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

Edit: 编译命令是:

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

1 回答

  • 4

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

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

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

    ..这显然不是这种情况 .
    's the key difference, and the reason that @dasblinkenlight'的引用与此事无关:默认构造函数从未定义,因此缺少mem-initializer-id的段落不适用 .

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

    当为其类类型的对象分配其类类型的值或从其类类型派生的类类型的值时,将隐式定义隐式声明的复制赋值运算符 . 如果隐式定义了复制赋值运算符的类具有以下类型,则程序格式不正确:const类型的非静态数据成员,或[..]

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

    举个例子,拿

    struct A
    {
        int i;
        const int b;
    };
    
    int main()
    {
        A a = {1, 1};
    }
    

    哪个compiles fine under GCC . 您的计划也应该是格式良好的,因为所有关于工会成员特殊成员职能的要求都由 A 满足 .

相关问题