6

You can't forward declare an enum in C++, but you can in C.

For a C code-base that uses some C++ code, is there a way to use a forward declared enum in C that doesn't cause errors when that header is used in C++ (within an extern "C" {..} block)?

Example:

extern "C" {
    enum MyEnum;
}
int main() { return 0; }

GCC gives the error:

error: use of enum ‘MyEnum’ without previous declaration
  enum MyEnum;
       ^~~~~~

Clang also fails with:

error: ISO C++ forbids forward references to 'enum' types
        enum MyEnum;

To give some context, this is a mainly C code-base where a small C++ module happens to include a header for C code. I can do some hack to make C++ ignore the enum, but I would like to know if its possible for C++ to use C headers in this case.


Update: It's been noted the official C specification doesn't support this. However, it seems this is a de facto standard among some of the most widely used compilers: GCC, Clang, and Microsoft Visual C++.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ideasman42
  • 42,413
  • 44
  • 197
  • 320

3 Answers3

5

You can forward-declare enum in C++ starting from C++11. It's called "opaque declaration" rather than "forward declaration" because technically it results in a bit different effect: the size of the enum is known after its opaque declaration, while with the forward-declared types that's not the case.

However, from the daily perspective it's the same idea: you can just declare your enum and use it further in the code. From cppreference:

enum-key attr(optional) nested-name-specifier(optional) identifier enum-base(optional) ;(2) (since C++11)

2) Opaque enum declaration: defines the enumeration type but not its enumerators: after this declaration, the type is a complete type and its size is known. Note: an explicit specialization declaration of a scoped enumeration member of a class template is the only case where nested-name-specifier appears before identifier (since C++14)

Vasiliy Galkin
  • 1,894
  • 1
  • 14
  • 25
5

Forward declaration of enums in C just makes no sense. Enums in C only introduce integral enumeration constants. They don't introduce any types you would want to use. Each enum type is an unspecified integral type, compatible with all other integral types, so there isn't any type safety at all.

typedef enum e12 { ONE, TWO } e12;
typedef enum e34 { THREE, FOUR } e34;
int main () {
    e12 one = ONE;
    e34 three = THREE;
    one = three;
    three = ONE;
    return one + three;
}

This C program compiles cleanly with GCC on -Wall -Wextra -Wpedantic (it won't work as a C++ program of course).

So a useful portable cross-language solution would be

#ifdef __cplusplus
   enum MyEnum : int;
#else
   typedef int MyEnum; // 'enum MyEnum' would give no improvement over this
#endif
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 5
    There is some advantage in using enums over ints - with GCC/Clang there are enum-aware warnings (`-Wenum-compare`, `-Wswitch-enum`), address sanitizer has `-fsanitize=enum` - while not guarantees, they can be used to uncover real errors in the code which you wouldn't detect using regular ints. – ideasman42 Aug 24 '17 at 11:29
1

This can be done in C++11, (see @vasiliy-galkin's answer), an example of how this can work for shared C/C++ headers.

C header forward declaring MyEnum.

#ifdef __cplusplus
extern "C" {
#endif

enum MyEnum
#ifdef __cplusplus
: int
#endif
;

#ifdef __cplusplus
}
#endif
ideasman42
  • 42,413
  • 44
  • 197
  • 320