为什么opaque-enum-declaration不是定义?

时间:2014-04-28 12:43:00

标签: c++ c++11 language-lawyer

§3.1/ 2表示 opaque-enum-declaration 定义的声明。然而它占据了记忆中的空间。将它与同样具有大小的定义类进行比较。两者都是标准的完整类型。为什么一个是声明而另一个是定义?

#include <iostream>
enum A : int;   // opaque-enum-declaration
class B{};      // a class definition

int main() {
    std::cout << sizeof(A) << '\n';
    std::cout << sizeof(B) << '\n';
}

输出

  

4

     

1

修改

我可以理解下面的opaque-enum-declaration enum A : int;

#include <iostream>
enum A : int;   // opaque-enum-declaration

int main() {
    A a;
    std::cout << a << '\n';
}

EDIT1

就变量a而言,前一个片段和下面的片段之间没有区别。它们都保留变量undefined。因此,很难接受enum : int;是一个声明而enum A : int {quick, brown, fox};是一个定义。

#include <iostream>
enum A : int {quick, brown, fox};

int main() {
    A a;
    std::cout << a << '\n';
}

3 个答案:

答案 0 :(得分:2)

大小只是enum的一个方面。尽管编译器知道大小足以让您在其他声明或定义中使用enum,但enum本身仍然未定义,直到您枚举其成员为止。本质上,enum A : int向编译器承诺两件事 - 即

  • 其他地方定义了enum A
  • enum A的所有成员都将拥有适合int
  • 的值

一旦编译器发现enum A的定义,它会检查成员是否足够小于声明的大小,并考虑定义enum。从那时起,提供相同enum A的另一个定义是错误的。

相比之下,你的class B已经完全完成了:你告诉编译器class B将是空的;你不能为它提供一个替代定义,给它一些成员。

编辑:

  

opaque-enum-declaration枚举A:int;以下是我所能理解的定义。

XYZ在您的计划中的某个点之后才被视为已定义,之后提供XYZ的定义构成错误。为此,enum A在您的计划中仍然未定义,因为您可以在main之后定义它,如下所示:

#include <iostream>
enum A : int; // opaque-enum-declaration

int main() {
    A a;
    std::cout << a << '\n';
}
// This is allowed
enum A : int {quick, brown, fox};

顺便说一句,这并不妨碍您的程序成功编译,因为在C ++中 undefined 不等同于不可用

答案 1 :(得分:2)

类型为完整,但在 opaque-enum-declaration 之后

  

7.2 [dlc.enum] / 3

     

opaque-enum-declaration是枚举的重新声明   在当前范围或新枚举的声明中。 [注意:安   由opaque-enum-declaration声明的枚举已修复   基础类型,是一个完整的类型。(枚举器列表可以是   在后来的重新声明中提供了一个enumspecifier。 - 注意事项] A.   范围的枚举不得在以后重新声明为无范围或具有   不同的基础类型。不受限制的查点不得晚于   重新声明为范围,每个重新声明应包括枚举   指定与原始声明中相同的基础类型。

上面的完整类型表示只要看到 opaque-enum-declaration 就可以使用sizeof成为你的顾虑。它仍然不是定义,因为定义需要指定类型的所有方面, opaque-enum-declaration 不会。

如果要将其与类定义进行比较, opaque-enum-declaration 将等同于包含所有非静态数据成员的类[half]定义和表示是否的属性将存在虚函数,但不声明任何成员函数。对象的大小很清楚,但不是如何使用它。

答案 2 :(得分:0)

本声明

enum A : int;

是一份声明。这意味着声明名称A表示某种范围的枚举类型。它不占用记忆。

本声明

class B{};      

也是一个类声明。它也被称为类定义,因为它定义了类的结构。但是这个声明并没有占用记忆。枚举或类类型的对象占用内存。这些陈述

std::cout << sizeof(A) << '\n';
std::cout << sizeof(B) << '\n';

显示如果某个对象被定义为具有这些类型之一,则可以占用多少内存。

考虑以下代码

#include <iostream>

int main()
{
   std::cout << sizeof( int ) << std::endl;
}

此代码输出int类型的对象的大小。但是程序中没有定义任何对象。

将上面的代码与以下代码进行比较

#include <iostream>

int main()
{
   int x;
   std::cout << sizeof( x ) << std::endl;
}

在此程序中定义了x类型的对象。它确实占据了记忆。 int只是一个简单的类型说明符。代码中的A和B的方式与类型说明符相同。类型说明符只是一些描述。他们没有占据记忆。