包含常量成员的POD结构 [英] POD structs containing constant member

查看:137
本文介绍了包含常量成员的POD结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用此代码:

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

//联合是验证A是可以在联合中使用的类型。
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'AU :: a'不允许在联合中使用复制赋值运算符
A a;
^
a.cpp:9:4:注意:无限制工会只能使用-std = c ++ 11或-std = gnu ++ 11

但clang 3.5.0会无错编译此代码。哪一个是对的?这是一个编译器错误吗?



我尝试解决这个问题



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


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


+03 standard section 12.8 paragraph 10 and 11:


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



否则,隐式声明的拷贝赋值运算符将具有形式X& X :: operator =(X&)
...



类X的复制赋值运算符很简单如果它是隐式声明的,并且如果类X没有虚拟函数(10.3)和没有虚拟基类(10.1),并且X的每个直接基类都有一个简单的拷贝赋值运算符,对于X的所有非静态数据成员,类型(或其数组),每个这样的类类型具有简单的拷贝赋值运算符;


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



编辑:
编译命令是:

  clang ++ a.cpp -oa 
g ++ a.cpp -oa

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

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

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

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

  g ++ b.cpp -ob 
clang ++ b.cpp -ob


解决方案

正确地注意到,复制赋值操作符隐含地声明和微不足道。
默认构造函数也是如此,它也是微不足道的,并隐式声明。



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


一个隐式声明的默认构造函数



$ b当类用于创建类类型(1.8)的对象时,类是隐式地定义
$ b

..这显然不是这里的情况。

这是关键的区别,以及@ dasblinkenlight的引用与此事无关的原因:默认构造函数从未定义,因此段落



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


隐式声明的副本赋值操作符是隐式定义 类型被赋予其类类型的值或从其类类型派生的类类型的值。
如果类的副本赋值
运算符为 的非静态数据成员: code> type 或[..]

如果使用副本分配操作符,将是不合格的。但它不是。所有的特殊成员函数都是单独声明的,对非静态数据成员的 const 的任何限制只适用于隐式定义的特殊成员函数。



例如,

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

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

其中根据GCC编译罚款。由于 A


满足所有关于成员职能的特殊成员职能的特殊要求,您的计划也应该具有良好的形式

With this code:

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++ version 4.8.3 complains about an error:

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

but clang 3.5.0 compiles this code without error. Which one is correct? Is this a compiler bug?

My attempt at solving this:

From the C++03 standard section 9.5 paragraph 1:

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. [Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ] The size of a union is sufficient to contain the largest of its data members. Each data member is allocated as if it were the sole member of a struct. A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects. If a union contains a static data member, or a member of reference type, the program is ill-formed.

From the C++03 standard section 12.8 paragraphs 10 and 11:

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. The implicitly-declared copy assignment operator for a class X will have the form X& X::operator=(const X&) if each direct base class B of X has a copy assignment operator whose parameter is of type const B&, const volatile B& or B, and for all the nonstatic data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.

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

A copy assignment operator for class X is trivial if it is implicitly declared and if class X has no virtual functions (10.3) and no virtual base classes (10.1), and each direct base class of X has a trivial copy assignment operator, and for all the nonstatic data members of X that are of class type (or array thereof), each such class type has a trivial copy assignment operator; otherwise the copy assignment operator is non-trivial.

I'm not sure which compiler is correct because I don't know if a constant member has a trivial copy assignment operator.

Edit: The compilation commands are:

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

Edit2: To show that g++ isn't complaining about A::b being const but A doesn't have a constructor, I also tried this program:

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

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

This compiled without errors on both g++ and clang++:

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

解决方案

As correctly noted by you the copy assignment operator is implicitly declared and trivial. Same goes for the default constructor, which is also trivial and implicitly declared.

Note though that both of these member functions aren't implicitly defined - that only happens when they are used, [class.ctor]/7:

An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8).

.. which is clearly not the case here.
That's the key difference, and the reason that @dasblinkenlight's quote is irrelevant for this matter: The default constructor is never defined, thus the paragraph on missing mem-initializer-ids doesn't apply.

How are const members and the assignment operator connected then? Here:

An implicitly-declared copy assignment operator is implicitly defined when an object of its class type is assigned a value of its class type or a value of a class type derived from its class type. A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:

  • a nonstatic data member of const type, or [..]

Thus the program would be ill-formed if the copy assignment operator would be used. But it isn't. All the special member functions are solely declared, and any restrictions on the const-ness of non-static data members only apply on implicitly defined special member functions.

As an example, take

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

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

Which compiles fine under GCC. Your program should be well-formed, too, as all requirements on trivialty of special member functions of union members are met by A.

这篇关于包含常量成员的POD结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆