Question

§3.1/2 says that an opaque-enum-declaration is a declaration that is not a definition. Nevertheless it occupies space in memory. Compare it with a class definition that also has a size. Both are complete types by the Standard. Why one is a declaration and the other is a definition?

#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';
}

Output

4

1

Edit

The opaque-enum-declaration enum A : int; below is defined as far as I can understand.

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

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

Edit1

As far as the variable a is concerned, there's no difference between the prior snippet and the one below. They both leave the variable undefined. Thus, it's difficult to accept that enum : int; is a declaration and enum A : int {quick, brown, fox}; is a definition.

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

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

Solution

The type is complete, although not defined after an opaque-enum-declaration:

7.2 [dlc.enum]/3

An opaque-enum-declaration is either a redeclaration of an enumeration in the current scope or a declaration of a new enumeration. [ Note: An enumeration declared by an opaque-enum-declaration has fixed underlying type and is a complete type.( The list of enumerators can be provided in a later redeclaration with an enumspecifier. —end note ] A scoped enumeration shall not be later redeclared as unscoped or with a different underlying type. An unscoped enumeration shall not be later redeclared as scoped and each redeclaration shall include an enum-base specifying the same underlying type as in the original declaration.

The complete type above means that you can use sizeof after just seeing the opaque-enum-declaration, which seems to be your concern. It is still not a definition, as a definition require all aspects of the type to be specified, which the opaque-enum-declaration does not.

If you were to compare this with a class definition, the opaque-enum-declaration would be the equivalent of a class [half] definition containing all non-static data members and an attribute stating whether virtual functions will be present, but without declaring any of the member functions. The size of the object would be clear, but not how to use it.

OTHER TIPS

This statement

enum A : int;

is a declaration. It means that name A is declared to denote some scoped enumeration type. It does not occupy memory.

This statement

class B{};      

is also a class declaration. It is called also a class definition because it defines the structure of the class. However this declaration does not occupy memory. It is an object of an enumeration or class type that occupies memory. These statement

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

show how many memory could occupy an object if it would be defined as having one of these types.

Consider the following code

#include <iostream>

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

This code outputs the size of objects of type int. However neither object was defined in the program.

And compare the code above with the following code

#include <iostream>

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

In this program an object of type x was defined. It does indeed occupy memory. int is only a simple type specifer. The same way A and B from your code are type specifiers. Type specifiers are only some desciptions. They do not occupy memory.

Size is only one aspect of an enum. Although it is enough for the compiler to know the size in order to let you use your enum in other declarations or definitions, the enum itself remains undefined until you enumerate its members. In essence, enum A : int promises the compiler two things - namely, that

  • There is an enum A defined some place else, and
  • All members of enum A will have values that fit in an int.

Once the compiler discovers the definition of enum A, it checks that the members are small enough for the declared size, and considers the enum defined. From that point on, providing another definition of the same enum A is an error.

In contrast, your class B is already fully complete: you told the compiler that class B is going to be empty; you cannot provide an alternative definition for it, giving it some members.

EDIT :

The opaque-enum-declaration enum A : int; below is defined as far as I can understand.

XYZ is not considered defined until a point in your program after which providing a definition of XYZ constitutes an error. To that end, enum A remains undefined in your program, because you are allowed to define it after main, like this:

#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};

Incidentally, this does not prevent your program from compiling successfully, because in C++ undefined is not an equivalent of unusable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top