Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cannot forward declare a scoped enum?

Tags:

c++

c++11

The title is already the question.
More details: the standard enacts:

If the enum-key is followed by a nested-name-specifier, the enum-specifier shall refer to an enumeration that was previously declared directly in the class or namespace to which the nested-name-specifier refers (i.e., neither inherited nor introduced by a using-declaration), and the enum-specifier shall appear in a namespace enclosing the previous declaration.

at 7.2, paragraph 4. For example, this prohibits to forward-declare an enum defined inside a class:

struct S{
  enum foo{A, B};
};

now, S can be forward-declared, while S::foo not.

Question is about why. Is there a situation in which this rule can be a benefit? Why is it needed? Or, if you prefer: if the standard had not this rule, is there a situation in which the compiler would have a problem? Which one(s)?

like image 915
fedino Avatar asked Oct 05 '16 09:10

fedino


People also ask

Can you forward declare enum?

Forward Declaration of Enums (C++11) BCC32 introduces forward declaration of enums. You can declare an enumeration without providing a list of enumerators. Such declarations would not be definitions and can be provided only for enumerations with fixed underlying types.

What is a scoped enum?

A scoped enum looks exactly as a traditional enum except that the keyword class (or struct – the two keywords are interchangeable in this context) appears between the keyword enum and the enum name, as shown in the following example: enum class Color //C++11 scoped enum.

What is function forward declaration?

A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier. In the case of functions, this allows us to tell the compiler about the existence of a function before we define the function's body.


1 Answers

At least, if forward-declare an enum was allowed, it would have created problems with template specializations like the one in the following example:

// somewhere in a .cpp

template<typename>
struct S;

enum S<int>::E;

// somewhere in a galaxy far, far away

template<typename>
struct S { enum class E {}; };

template<>
struct S<int> {};

How could the compiler know (and verify) that enum S<int>::E; is actually defined?


That said, even when you deal with namespaces you cannot do this:

struct X::A;
namespace X { struct A {}; }

But you can do this:

namespace X { struct A; }
namespace X { struct A {}; }

Using classes would result in a code like the following one:

struct A { enum E; };
struct A { enum E {} };

Anyway, this would violate the odr and it is not allowed.


Now, I'll try to give you my impression about the why.
If a forward-declaration of that type was allowed, you would have been allowed to give a partial definition of the containing class.
In other terms, consider this: enum S::E. This states firmly that S contains the enum class E, thus you are giving a clue about the definition of S. To speak not in standardese (that is far from being my natural language) you are partially defining S, thus the compiler should know that S has its definition somewhere plus it must have a definition for E too (either as part of the primary definition or as an out-of-class definition).
This would break the odr rules when the actual definition comes into view, so it cannot be allowed in any case, but as an exception of the basics rules of the language.
Moreover, this is a great source of headaches.

My two cents.

like image 50
skypjack Avatar answered Sep 21 '22 15:09

skypjack