Forward declaring an enum in C++ defined in C

I searched about forward declarations and didn't see any way to make my situation work. So here it is:

1) There is a C-header file. It is an export interface so to speak for a large multi-component software that contains an enum typedef


// This is in "C"!
typedef enum _VM_TYPE {...., ...., ...,} VM_TYPE;

2) A part of the code, in C++, uses that export.


// This is in C++
#include "export.h"
#include "cpp_header.hpp"
{ .... using VM_TYPE values to do stuffs....}


// I need to somehow forward declare VM_TYPE here, but how?
Struct VM_INFO {
    VM_TYPE VType; // I need to add this enum to the struct

So quite obviously, the problem is in file cpp_head.hpp, as it doesn't know about the enum.

I tried adding to cpp_header.hpp:

typedef enum _VM_TYPE VM_TYPE;

And it'll actually work. So why does this work? Is it because it has C-style syntax?! Anyway, I was told to not do that ("it's C++, not C here") by upper "management".

Is there another way to make this work at all, based on how things are linked currently? They don't want to change/add include files; "enum class" is C++ only, correct? Adding just "enum VM_TYPE" to cpp_header.hpp will get error about redefinition.

What can I do?


  • In the particular situation described in your question, you don't need to forward declare at all. All the files you #include are going to essentially get copy-pasted into a single translation unit before compilation proper begins, and since you #include "export.h" before you #include "cpp_header.hpp", then it'll just work, because by the time the compiler sees the definition of struct VM_INFO, it'll already have seen the definition of enum _VM_TYPE, so you've got no problem. There's basically no difference here between including "export.h" in "cpp_header.hpp", and including them both in "cpp_code.cpp" in that order, since you end up with essentially the same code after preprocessing. So all you have to do here is make sure you get your includes in the correct order.

    If you ever wanted to #include "cpp_header.hpp" without including "export.h" in a translation unit where you need to access the members of struct VM_INFO (so that leaving it as an incomplete type isn't an option) then "export.h" is just badly designed, and you should break out the definition of anything you might need separately into a new header. If, as the comments suggest, you absolutely cannot do this and are required to have a suboptimal design, then your next best alternative would be to have two versions of "cpp_header.hpp", one which just repeats the definition of enum _VM_TYPE, and one which does not. You'd #include the first version in any translation unit where you do not also #include "export.h", and #include the second version in any translation unit where you do. Obviously any code duplication of this type is inviting problems in the future.

    Also, names beginning with an underscore and a capital letter are always reserved in C, so you really shouldn't use them. If a future version of C ever decides to make use of _VM_TYPE, then you'll be stuck with either using an outdated version of C, or having all this code break.