为什么在前向声明时必须提供枚举的大小?

2021-12-29 00:00:00 enums forward-declaration c++ c++11

我只是不明白为什么枚举的大小与编译器相关,而类的大小则不然.

我的代码示例:

A类;枚举 E;//必须是枚举 E : int;为了编译void f(const A & param);void f(const E & param);

我在这里谈论的是标准 C++ 编译器.我知道 MSVC 让它编译并正常工作.所以问题是:

为什么没有标准化?

解决方案

这个已经标准化了,提案 2764:枚举的前向声明(修订版 3) 如果指定基础类型,则允许前向声明枚举,而在此之前这是不可能的.>

主要原因是当未指定底层类型时,大小是实现定义的并且可以依赖于枚举器值.来自 C++11 标准部分草案 7.2 [dcl.enum]:

<块引用>

对于底层类型不固定的枚举,底层type 是可以表示所有枚举值的整数类型枚举中定义.如果没有整数类型可以表示所有枚举值,枚举格式错误.它是实现定义的整数类型用作底层type 除了基础类型不能大于 int除非枚举器的值不能放入 int 或 unsigned内部如果枚举器列表为空,则底层类型就像枚举有一个值为 0 的枚举器.

当按值传递时,不知道底层类型是一个问题是有道理的,但是当它是指针或引用时为什么会成为问题?这很重要,因为在某些架构上,char* 和 int* 可以具有不同的大小,如本 comp.lang.c++ 讨论:GCC 和 enum 的前向声明:

<块引用>

[...] 虽然在大多数架构上这可能不是问题,但在某些架构指针将具有不同的大小,如果它是字符指针.所以最后我们想象中的编译器会不知道放什么来获得 ColorsEnum*[...]

我们有以下 stackoverflow 答案供参考,它描述了 char* 可以大于 int* 的情况,其中支持上述讨论中的断言.

一些更多关于可能的指针大小的细节它看起来像char *void * 是这里的两个主要例外,因此其他对象指针不应该有相同的问题.因此,这种情况似乎最终是枚举所独有的.

I just can't see why the size of the enumeration is relevant for the compiler while the size of the class is not.

My code example:

class A;
enum E;   // must be enum E : int; in order to compile 

void f(const A & param);
void f(const E & param);

I'm talking here of standard C++ compilers. I know that MSVC let it compile and works fine. So the question is:

Why this has not been standardized?

解决方案

This has been standardized, proposal 2764: Forward declaration of enumerations (rev. 3) allowed the forward declaration of enums if you specify the underlying type, whereas before this was not possible.

The main reason is that when the underlying type is not specified the size is implementation defined and can depend on the enumerator values. From the draft C++11 standard section 7.2 [dcl.enum]:

For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0.

When passing by value it makes sense that not knowing the underlying type is an issue, but why is it an issue when it is a pointer or reference? This matters since apparently on some architectures, char* and int* can have different sizes as mentioned in this comp.lang.c++ discussion: GCC and forward declaration of enum:

[...] While on most architectures it may not be an issue, on some architectures the pointer will have a different size, in case it is a char pointer. So finally our imaginary compiler would have no idea what to put there to get a ColorsEnum*[...]

We have the following stackoverflow answer for reference which describes the case where char* can be larger than int*, which backs up the assertion in the discussion above.

Some more details on the possible sizes of pointers it looks like char * and void * are the two main exceptions here and so other object pointers should not have the same issues. So it seems like this case ends up being unique to enums.

相关文章