C - forward declaration of enums?
Put them in a header so that all files that need them can access the header and use the declarations from it.
When compiled with the options:
$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -c enum.c
$
GCC 4.2.1 (on MacOS X 10.7.1) accepts the following code:
enum xyz;
struct qqq { enum xyz *p; };
enum xyz { abc, def, ghi, jkl };
Add -pedantic
and it warns:
$ /usr/bin/gcc -g -std=c99 -Wall -Wextra -pedantic -c enum.c
enum.c:1: warning: ISO C forbids forward references to ‘enum’ types
enum.c:5: warning: ISO C forbids forward references to ‘enum’ types
$
Thus, you are not supposed to try using forward declarations of enumerated types in C; GCC allows it as an extension when not forced to be pedantic.
Forward declaring an enum in C++
The reason the enum can't be forward declared is that, without knowing the values, the compiler can't know the storage required for the enum variable. C++ compilers are allowed to specify the actual storage space based on the size necessary to contain all the values specified. If all that is visible is the forward declaration, the translation unit can't know what storage size has been chosen – it could be a char
, or an int
, or something else.
From Section 7.2.5 of the ISO C++ Standard:
The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration. It is implementation-defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not be larger than
int
unless the value of an enumerator cannot fit in anint
orunsigned int
. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value ofsizeof()
applied to an enumeration type, an object of enumeration type, or an enumerator, is the value ofsizeof()
applied to the underlying type.
Since the caller to the function must know the sizes of the parameters to correctly set up the call stack, the number of enumerations in an enumeration list must be known before the function prototype.
Update:
In C++0X, a syntax for forward declaring enum types has been proposed and accepted. You can see the proposal at Forward declaration of enumerations (rev.3)
Enum Forward Declaration
Before C++11, C++ didn't support forward-declaration of enums at all! However, some compilers (like MS Visual Studio) provide language extensions for that.
If your compiler doesn't support C++11, look in its documentation on enum forward declarations.
If you can use C++11, there is the enum class
syntax (you almost got it right, but pay attention to the additional class
keyword:
// Forward declaration
enum class myEnumProcessState: unsigned int;
// Usage in a struct
struct myStruct {myEnumProcessState osState;};
// Full declaration in another header
enum class myEnumProcessState: unsigned int {
eNotRunning,
eRunning
};
// Usage of symbols (syntax may seem slightly unusual)
if (myObject.osState == myEnumProcessState::eNotRunning) {
...
}
enum class underlying type with forward declaration
The enum
's underlying type could be previously defined by means of typedef
:
typedef bool e_mode_base_t;
Then, you can use this type for the enum
's forward declaration:
enum class e_mode: e_mode_base_t;
and for the enum
's definition as well:
enum class e_mode : e_mode_base_t
{
SYNC,
ASYNC
};
This way, you only need to modify the definition of e_mode_base_t
when you wish to change the enum
's underlying type.
You could as well create a type alias by means of using
instead of typedef
:
using e_mode_base_t = bool;
which may be more readable.
Forward declared enum as class member variable
A forward declared enum class has a specified underlying type. If not explicitly specified it is int
. Because of that the storage size of the enum is known, even if it's only forward declared, so using it as a member is not a problem.
Related Topics
Forward Declaration of Nested Types/Classes in C++
Why Doesn't a Simple "Hello World"-Style Program Compile With Turbo C++
Should I Use Static_Cast or Reinterpret_Cast When Casting a Void* to Whatever
What Are the Mechanics of Short String Optimization in Libc++
How to Create a Dynamic Array of Integers
Variadic Template Pack Expansion
C++ Cross-Platform High-Resolution Timer
How to Properly Delete Nodes of Linked List in C++
How to Have Functions Inside Functions in C++
Difference Between _Tmain() and Main() in C++
C++ Templates That Accept Only Certain Types
Why Does Cout Print Char Arrays Differently from Other Arrays