Enum forward declaration vs. header files - c++

In the LearnCPP CH4.5 Enumerated Types, it states
Because the compiler needs to know how much memory to allocate for an enumeration, you cannot forward declare enum types. However, there is an easy workaround. Because defining an enumeration does not allocate any memory, if an enumeration is needed in multiple files, it is fine to define the enumeration in a header, and #include that header wherever needed.
I thought header files are collection of forward declarations but just in a separate file. Then why would declaring an enumeration type in the header file any different as forward declaring in the same file that it is being used?

The statement here is not really about where the enumeration is declared, it is about the difference between a declaration and a definition.
Something like
enum MyEnum; // just a declaration, not a definition
struct Foo {
MyEnum value;
};
fails to compile because the compiler can't determine the size of MyEnum just from the declaration, but needs that size to determine the size of the struct Foo defined in the snippet above.
This is in contrast to something like
// the following is both a declaration and a defintion of the enum `MyEnum`
enum MyEnum {
your,
enumerators,
go,
here
};
struct Foo {
MyEnum value;
};
which compiles because the compiler now has all required information to determine the size of struct Foo.
However, the source you quoted seems to be a little outdated. Since C++11 the declaration of an enum can suffice as long as its size is known, i.e. because you either explicitly specify the underlying type of an unscoped enum (e.g. enum MyEnum : unsigned int;) or because you use a scoped enum, which by default uses int as its underlying type. That is
enum MyEnum : int; // declaration only, but with specified underlying type
enum class Bar; // also only declaration, `int` is implicit underlying type
struct Foo {
MyEnum v1;
Bar v2;
};
compiles just fine.

Related

Why does C++ allow forward declaration of class but not enums? [duplicate]

I'm trying to do something like the following:
enum E;
void Foo(E e);
enum E {A, B, C};
which the compiler rejects. I've had a quick look on Google and the consensus seems to be "you can't do it", but I can't understand why. Can anyone explain?
Clarification 2: I'm doing this as I have private methods in a class that take said enum, and I do not want the enum's values exposed - so, for example, I do not want anyone to know that E is defined as
enum E {
FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}
as project X is not something I want my users to know about.
So, I wanted to forward declare the enum so I could put the private methods in the header file, declare the enum internally in the cpp, and distribute the built library file and header to people.
As for the compiler - it's GCC.
Forward declaration of enums is possible since C++11. Previously, the reason enum types couldn't be forward declared was because the size of the enumeration depended on its contents. As long as the size of the enumeration is specified by the application, it can be forward declared:
enum Enum1; // Illegal in C++03 and C++11; no size is explicitly specified.
enum Enum2 : unsigned int; // Legal in C++11.
enum class Enum3; // Legal in C++11, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; // Legal C++11.
enum Enum2 : unsigned short; // Illegal in C++11, because Enum2 was previously declared with a different type.
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() 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)
You can forward-declare an enum in C++11, so long as you declare its storage type at the same time. The syntax looks like this:
enum E : short;
void foo(E e);
....
enum E : short
{
VALUE_1,
VALUE_2,
....
}
In fact, if the function never refers to the values of the enumeration, you don't need the complete declaration at all at that point.
This is supported by G++ 4.6 and onwards (-std=c++0x or -std=c++11 in more recent versions). Visual C++ 2013 supports this; in earlier versions it has some sort of non-standard support that I haven't figured out yet - I found some suggestion that a simple forward declaration is legal, but your mileage may vary.
Forward declaring things in C++ is very useful because it dramatically speeds up compilation time. You can forward declare several things in C++ including: struct, class, function, etc...
But can you forward declare an enum in C++?
No, you can't.
But why not allow it? If it were allowed you could define your enum type in your header file, and your enum values in your source file. It sounds like it should be allowed, right?
Wrong.
In C++ there is no default type for enum like there is in C# (int). In C++ your enum type will be determined by the compiler to be any type that will fit the range of values you have for your enum.
What does that mean?
It means that your enum's underlying type cannot be fully determined until you have all of the values of the enum defined. Which means you cannot separate the declaration and definition of your enum. And therefore you cannot forward declare an enum in C++.
The ISO C++ standard S7.2.5:
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() applied to the underlying type.
You can determine the size of an enumerated type in C++ by using the sizeof operator. The size of the enumerated type is the size of its underlying type. In this way you can guess which type your compiler is using for your enum.
What if you specify the type of your enum explicitly like this:
enum Color : char { Red=0, Green=1, Blue=2};
assert(sizeof Color == 1);
Can you then forward declare your enum?
No. But why not?
Specifying the type of an enum is not actually part of the current C++ standard. It is a VC++ extension. It will be part of C++0x though.
Source
[My answer is wrong, but I've left it here because the comments are useful].
Forward declaring enums is non-standard, because pointers to different enum types are not guaranteed to be the same size. The compiler may need to see the definition to know what size pointers can be used with this type.
In practice, at least on all the popular compilers, pointers to enums are a consistent size. Forward declaration of enums is provided as a language extension by Visual C++, for example.
There is indeed no such thing as a forward declaration of enum. As an enum's definition doesn't contain any code that could depend on other code using the enum, it's usually not a problem to define the enum completely when you're first declaring it.
If the only use of your enum is by private member functions, you can implement encapsulation by having the enum itself as a private member of that class. The enum still has to be fully defined at the point of declaration, that is, within the class definition. However, this is not a bigger problem as declaring private member functions there, and is not a worse exposal of implementation internals than that.
If you need a deeper degree of concealment for your implementation details, you can break it into an abstract interface, only consisting of pure virtual functions, and a concrete, completely concealed, class implementing (inheriting) the interface. Creation of class instances can be handled by a factory or a static member function of the interface. That way, even the real class name, let alone its private functions, won't be exposed.
I am just noting that the reason actually is that the size of the enum is not yet known after forward declaration. Well, you use forward declaration of a struct to be able to pass a pointer around or refer to an object from a place that's referred to in the forward declared struct definition itself too.
Forward declaring an enum would not be too useful, because one would wish to be able to pass around the enum by-value. You couldn't even have a pointer to it, because I recently got told some platforms use pointers of different size for char than for int or long. So it all depends on the content of the enum.
The current C++ Standard explicitly disallows doing something like
enum X;
(in 7.1.5.3/1). But the next C++ Standard due to next year allows the following, which convinced me the problem actually has to do with the underlying type:
enum X : int;
It's known as an "opaque" enum declaration. You can even use X by value in the following code. And its enumerators can later be defined in a later redeclaration of the enumeration. See 7.2 in the current working draft.
I'd do it this way:
[in the public header]
typedef unsigned long E;
void Foo(E e);
[in the internal header]
enum Econtent { FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X,
FORCE_32BIT = 0xFFFFFFFF };
By adding FORCE_32BIT we ensure that Econtent compiles to a long, so it's interchangeable with E.
You can wrap the enum in a struct, adding in some constructors and type conversions, and forward declare the struct instead.
#define ENUM_CLASS(NAME, TYPE, VALUES...) \
struct NAME { \
enum e { VALUES }; \
explicit NAME(TYPE v) : val(v) {} \
NAME(e v) : val(v) {} \
operator e() const { return e(val); } \
private:\
TYPE val; \
}
This appears to work:
http://ideone.com/TYtP2
If you really don't want your enum to appear in your header file and ensure that it is only used by private methods, then one solution can be to go with the PIMPL principle.
It's a technique that ensure to hide the class internals in the headers by just declaring:
class A
{
public:
...
private:
void* pImpl;
};
Then in your implementation file (.cpp), you declare a class that will be the representation of the internals.
class AImpl
{
public:
AImpl(A* pThis): m_pThis(pThis) {}
... all private methods here ...
private:
A* m_pThis;
};
You must dynamically create the implementation in the class constructor and delete it in the destructor and when implementing public method, you must use:
((AImpl*)pImpl)->PrivateMethod();
There are pros for using PIMPL. One is that it decouples your class header from its implementation, and there isn't any need to recompile other classes when changing one class implementation. Another is that is speeds up your compilation time, because your headers are so simple.
But it's a pain to use, so you should really ask yourself if just declaring your enum as private in the header is that much a trouble.
There's some dissent since this got bumped (sort of), so here's some relevant bits from the standard. Research shows that the standard doesn't really define forward declaration, nor does it explicitly state that enums can or can't be forward declared.
First, from dcl.enum, section 7.2:
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 an int or
unsigned int. If the enumerator-list
is empty, the underlying type is as if
the enumeration had a single
enumerator with value 0. The value of
sizeof() applied to an enumeration
type, an object of enumeration type,
or an enumerator, is the value of
sizeof() applied to the underlying
type.
So the underlying type of an enum is implementation-defined, with one minor restriction.
Next we flip to the section on "incomplete types" (3.9), which is about as close as we come to any standard on forward declarations:
A class that has been declared but not defined, or an array of unknown size or of
incomplete element type, is an incompletely-defined object type.
A class type (such as "class X") might be incomplete at one point in a translation
unit and complete later on; the type "class X" is the same type at both points. The
declared type of an array object might be an array of incomplete class type and
therefore incomplete; if the class type is completed later on in the translation unit,
the array type becomes complete; the array type at those two points is the same type.
The declared type of an array object might be an array of unknown size and therefore be
incomplete at one point in a translation unit and complete later on; the array types at
those two points ("array of unknown bound of T" and "array of N T") are different
types. The type of a pointer to array of unknown size, or of a type defined by a typedef
declaration to be an array of unknown size, cannot be completed.
So there, the standard pretty much laid out the types that can be forward declared. Enum wasn't there, so compiler authors generally regard forward declaring as disallowed by the standard due to the variable size of its underlying type.
It makes sense, too. Enums are usually referenced in by-value situations, and the compiler would indeed need to know the storage size in those situations. Since the storage size is implementation defined, many compilers may just choose to use 32 bit values for the underlying type of every enum, at which point it becomes possible to forward declare them.
An interesting experiment might be to try forward declaring an enum in Visual Studio, then forcing it to use an underlying type greater than sizeof(int) as explained above to see what happens.
In my projects, I adopted the Namespace-Bound Enumeration technique to deal with enums from legacy and 3rd-party components. Here is an example:
forward.h:
namespace type
{
class legacy_type;
typedef const legacy_type& type;
}
enum.h:
// May be defined here or pulled in via #include.
namespace legacy
{
enum evil { x , y, z };
}
namespace type
{
using legacy::evil;
class legacy_type
{
public:
legacy_type(evil e)
: e_(e)
{}
operator evil() const
{
return e_;
}
private:
evil e_;
};
}
foo.h:
#include "forward.h"
class foo
{
public:
void f(type::type t);
};
foo.cc:
#include "foo.h"
#include <iostream>
#include "enum.h"
void foo::f(type::type t)
{
switch (t)
{
case legacy::x:
std::cout << "x" << std::endl;
break;
case legacy::y:
std::cout << "y" << std::endl;
break;
case legacy::z:
std::cout << "z" << std::endl;
break;
default:
std::cout << "default" << std::endl;
}
}
main.cc:
#include "foo.h"
#include "enum.h"
int main()
{
foo fu;
fu.f(legacy::x);
return 0;
}
Note that the foo.h header does not have to know anything about legacy::evil. Only the files that use the legacy type legacy::evil (here: main.cc) need to include enum.h.
It seems it can not be forward-declared in GCC!
An interesting discussion is here.
For VC++, here's the test about forward declaration and specifying the underlying type:
The following code is compiled OK.
typedef int myint;
enum T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
enum T : char
{
A
};
But I got the warning for /W4 (/W3 does not incur this warning)
warning C4480: nonstandard extension used: specifying underlying type for enum 'T'
VC++ (Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86) looks buggy in the above case:
when seeing enum T; VC assumes the enum type T uses default 4 bytes int as underlying type, so the generated assembly code is:
?foo##YAXPAW4T###Z PROC ; foo
; File e:\work\c_cpp\cpp_snippet.cpp
; Line 13
push ebp
mov ebp, esp
; Line 14
mov eax, DWORD PTR _tp$[ebp]
mov DWORD PTR [eax], 305419896 ; 12345678H
; Line 15
pop ebp
ret 0
?foo##YAXPAW4T###Z ENDP ; foo
The above assembly code is extracted from /Fatest.asm directly, not my personal guess.
Do you see the
mov DWORD PTR[eax], 305419896 ; 12345678H
line?
the following code snippet proves it:
int main(int argc, char *argv)
{
union {
char ca[4];
T t;
}a;
a.ca[0] = a.ca[1] = a.[ca[2] = a.ca[3] = 1;
foo( &a.t) ;
printf("%#x, %#x, %#x, %#x\n", a.ca[0], a.ca[1], a.ca[2], a.ca[3] );
return 0;
}
The result is:
0x78, 0x56, 0x34, 0x12
After removing the forward declaration of enum T and move the definition of function foo after the enum T's definition: the result is OK:
The above key instruction becomes:
mov BYTE PTR [eax], 120 ; 00000078H
The final result is:
0x78, 0x1, 0x1, 0x1
Note the value is not being overwritten.
So using of the forward-declaration of enum in VC++ is considered harmful.
BTW, to not surprise, the syntax for declaration of the underlying type is same as its in C#. In pratice I found it's worth to save three bytes by specifying the underlying type as char when talking to the embedded system, which is memory limited.
My solution to your problem would be to either:
1 - use int instead of enums: Declare your ints in an anonymous namespace in your CPP file (not in the header):
namespace
{
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
}
As your methods are private, no one will mess with the data. You could even go further to test if someone sends you an invalid data:
namespace
{
const int FUNCTIONALITY_begin = 0 ;
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
const int FUNCTIONALITY_end = 3 ;
bool isFunctionalityCorrect(int i)
{
return (i >= FUNCTIONALITY_begin) && (i < FUNCTIONALITY_end) ;
}
}
2 : create a full class with limited const instantiations, like done in Java. Forward declare the class, and then define it in the CPP file, and instanciate only the enum-like values. I did something like that in C++, and the result was not as satisfying as desired, as it needed some code to simulate an enum (copy construction, operator =, etc.).
3 : As proposed before, use the privately declared enum. Despite the fact an user will see its full definition, it won't be able to use it, nor use the private methods. So you'll usually be able to modify the enum and the content of the existing methods without needing recompiling of code using your class.
My guess would be either the solution 3 or 1.
To anyone facing this for iOS/Mac/Xcode,
If you are facing this while integrating C/C++ headers in XCode with Objective-C, just change the extension of your file from .mm to .m
Because the enum can be an integral size of varying size (the compiler decides which size a given enum has), the pointer to the enum can also have varying size, since it's an integral type (chars have pointers of a different size on some platforms for instance).
So the compiler can't even let you forward-declare the enum and user a pointer to it, because even there, it needs the size of the enum.
You define an enumeration to restrict the possible values of elements of the type to a limited set. This restriction is to be enforced at compile time.
When forward declaring the fact that you will use a 'limited set' later on doesn't add any value: subsequent code needs to know the possible values in order to benefit from it.
Although the compiler is concerned about the size of the enumerated type, the intent of the enumeration gets lost when you forward declare it.
This way we can forward declare enum
enum A : int;
please refer the link for details.

Why not C++ (not C++0x) support enum forward declaration? [duplicate]

I'm trying to do something like the following:
enum E;
void Foo(E e);
enum E {A, B, C};
which the compiler rejects. I've had a quick look on Google and the consensus seems to be "you can't do it", but I can't understand why. Can anyone explain?
Clarification 2: I'm doing this as I have private methods in a class that take said enum, and I do not want the enum's values exposed - so, for example, I do not want anyone to know that E is defined as
enum E {
FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}
as project X is not something I want my users to know about.
So, I wanted to forward declare the enum so I could put the private methods in the header file, declare the enum internally in the cpp, and distribute the built library file and header to people.
As for the compiler - it's GCC.
Forward declaration of enums is possible since C++11. Previously, the reason enum types couldn't be forward declared was because the size of the enumeration depended on its contents. As long as the size of the enumeration is specified by the application, it can be forward declared:
enum Enum1; // Illegal in C++03 and C++11; no size is explicitly specified.
enum Enum2 : unsigned int; // Legal in C++11.
enum class Enum3; // Legal in C++11, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; // Legal C++11.
enum Enum2 : unsigned short; // Illegal in C++11, because Enum2 was previously declared with a different type.
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() 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)
You can forward-declare an enum in C++11, so long as you declare its storage type at the same time. The syntax looks like this:
enum E : short;
void foo(E e);
....
enum E : short
{
VALUE_1,
VALUE_2,
....
}
In fact, if the function never refers to the values of the enumeration, you don't need the complete declaration at all at that point.
This is supported by G++ 4.6 and onwards (-std=c++0x or -std=c++11 in more recent versions). Visual C++ 2013 supports this; in earlier versions it has some sort of non-standard support that I haven't figured out yet - I found some suggestion that a simple forward declaration is legal, but your mileage may vary.
Forward declaring things in C++ is very useful because it dramatically speeds up compilation time. You can forward declare several things in C++ including: struct, class, function, etc...
But can you forward declare an enum in C++?
No, you can't.
But why not allow it? If it were allowed you could define your enum type in your header file, and your enum values in your source file. It sounds like it should be allowed, right?
Wrong.
In C++ there is no default type for enum like there is in C# (int). In C++ your enum type will be determined by the compiler to be any type that will fit the range of values you have for your enum.
What does that mean?
It means that your enum's underlying type cannot be fully determined until you have all of the values of the enum defined. Which means you cannot separate the declaration and definition of your enum. And therefore you cannot forward declare an enum in C++.
The ISO C++ standard S7.2.5:
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() applied to the underlying type.
You can determine the size of an enumerated type in C++ by using the sizeof operator. The size of the enumerated type is the size of its underlying type. In this way you can guess which type your compiler is using for your enum.
What if you specify the type of your enum explicitly like this:
enum Color : char { Red=0, Green=1, Blue=2};
assert(sizeof Color == 1);
Can you then forward declare your enum?
No. But why not?
Specifying the type of an enum is not actually part of the current C++ standard. It is a VC++ extension. It will be part of C++0x though.
Source
[My answer is wrong, but I've left it here because the comments are useful].
Forward declaring enums is non-standard, because pointers to different enum types are not guaranteed to be the same size. The compiler may need to see the definition to know what size pointers can be used with this type.
In practice, at least on all the popular compilers, pointers to enums are a consistent size. Forward declaration of enums is provided as a language extension by Visual C++, for example.
There is indeed no such thing as a forward declaration of enum. As an enum's definition doesn't contain any code that could depend on other code using the enum, it's usually not a problem to define the enum completely when you're first declaring it.
If the only use of your enum is by private member functions, you can implement encapsulation by having the enum itself as a private member of that class. The enum still has to be fully defined at the point of declaration, that is, within the class definition. However, this is not a bigger problem as declaring private member functions there, and is not a worse exposal of implementation internals than that.
If you need a deeper degree of concealment for your implementation details, you can break it into an abstract interface, only consisting of pure virtual functions, and a concrete, completely concealed, class implementing (inheriting) the interface. Creation of class instances can be handled by a factory or a static member function of the interface. That way, even the real class name, let alone its private functions, won't be exposed.
I am just noting that the reason actually is that the size of the enum is not yet known after forward declaration. Well, you use forward declaration of a struct to be able to pass a pointer around or refer to an object from a place that's referred to in the forward declared struct definition itself too.
Forward declaring an enum would not be too useful, because one would wish to be able to pass around the enum by-value. You couldn't even have a pointer to it, because I recently got told some platforms use pointers of different size for char than for int or long. So it all depends on the content of the enum.
The current C++ Standard explicitly disallows doing something like
enum X;
(in 7.1.5.3/1). But the next C++ Standard due to next year allows the following, which convinced me the problem actually has to do with the underlying type:
enum X : int;
It's known as an "opaque" enum declaration. You can even use X by value in the following code. And its enumerators can later be defined in a later redeclaration of the enumeration. See 7.2 in the current working draft.
I'd do it this way:
[in the public header]
typedef unsigned long E;
void Foo(E e);
[in the internal header]
enum Econtent { FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X,
FORCE_32BIT = 0xFFFFFFFF };
By adding FORCE_32BIT we ensure that Econtent compiles to a long, so it's interchangeable with E.
You can wrap the enum in a struct, adding in some constructors and type conversions, and forward declare the struct instead.
#define ENUM_CLASS(NAME, TYPE, VALUES...) \
struct NAME { \
enum e { VALUES }; \
explicit NAME(TYPE v) : val(v) {} \
NAME(e v) : val(v) {} \
operator e() const { return e(val); } \
private:\
TYPE val; \
}
This appears to work:
http://ideone.com/TYtP2
If you really don't want your enum to appear in your header file and ensure that it is only used by private methods, then one solution can be to go with the PIMPL principle.
It's a technique that ensure to hide the class internals in the headers by just declaring:
class A
{
public:
...
private:
void* pImpl;
};
Then in your implementation file (.cpp), you declare a class that will be the representation of the internals.
class AImpl
{
public:
AImpl(A* pThis): m_pThis(pThis) {}
... all private methods here ...
private:
A* m_pThis;
};
You must dynamically create the implementation in the class constructor and delete it in the destructor and when implementing public method, you must use:
((AImpl*)pImpl)->PrivateMethod();
There are pros for using PIMPL. One is that it decouples your class header from its implementation, and there isn't any need to recompile other classes when changing one class implementation. Another is that is speeds up your compilation time, because your headers are so simple.
But it's a pain to use, so you should really ask yourself if just declaring your enum as private in the header is that much a trouble.
There's some dissent since this got bumped (sort of), so here's some relevant bits from the standard. Research shows that the standard doesn't really define forward declaration, nor does it explicitly state that enums can or can't be forward declared.
First, from dcl.enum, section 7.2:
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 an int or
unsigned int. If the enumerator-list
is empty, the underlying type is as if
the enumeration had a single
enumerator with value 0. The value of
sizeof() applied to an enumeration
type, an object of enumeration type,
or an enumerator, is the value of
sizeof() applied to the underlying
type.
So the underlying type of an enum is implementation-defined, with one minor restriction.
Next we flip to the section on "incomplete types" (3.9), which is about as close as we come to any standard on forward declarations:
A class that has been declared but not defined, or an array of unknown size or of
incomplete element type, is an incompletely-defined object type.
A class type (such as "class X") might be incomplete at one point in a translation
unit and complete later on; the type "class X" is the same type at both points. The
declared type of an array object might be an array of incomplete class type and
therefore incomplete; if the class type is completed later on in the translation unit,
the array type becomes complete; the array type at those two points is the same type.
The declared type of an array object might be an array of unknown size and therefore be
incomplete at one point in a translation unit and complete later on; the array types at
those two points ("array of unknown bound of T" and "array of N T") are different
types. The type of a pointer to array of unknown size, or of a type defined by a typedef
declaration to be an array of unknown size, cannot be completed.
So there, the standard pretty much laid out the types that can be forward declared. Enum wasn't there, so compiler authors generally regard forward declaring as disallowed by the standard due to the variable size of its underlying type.
It makes sense, too. Enums are usually referenced in by-value situations, and the compiler would indeed need to know the storage size in those situations. Since the storage size is implementation defined, many compilers may just choose to use 32 bit values for the underlying type of every enum, at which point it becomes possible to forward declare them.
An interesting experiment might be to try forward declaring an enum in Visual Studio, then forcing it to use an underlying type greater than sizeof(int) as explained above to see what happens.
In my projects, I adopted the Namespace-Bound Enumeration technique to deal with enums from legacy and 3rd-party components. Here is an example:
forward.h:
namespace type
{
class legacy_type;
typedef const legacy_type& type;
}
enum.h:
// May be defined here or pulled in via #include.
namespace legacy
{
enum evil { x , y, z };
}
namespace type
{
using legacy::evil;
class legacy_type
{
public:
legacy_type(evil e)
: e_(e)
{}
operator evil() const
{
return e_;
}
private:
evil e_;
};
}
foo.h:
#include "forward.h"
class foo
{
public:
void f(type::type t);
};
foo.cc:
#include "foo.h"
#include <iostream>
#include "enum.h"
void foo::f(type::type t)
{
switch (t)
{
case legacy::x:
std::cout << "x" << std::endl;
break;
case legacy::y:
std::cout << "y" << std::endl;
break;
case legacy::z:
std::cout << "z" << std::endl;
break;
default:
std::cout << "default" << std::endl;
}
}
main.cc:
#include "foo.h"
#include "enum.h"
int main()
{
foo fu;
fu.f(legacy::x);
return 0;
}
Note that the foo.h header does not have to know anything about legacy::evil. Only the files that use the legacy type legacy::evil (here: main.cc) need to include enum.h.
It seems it can not be forward-declared in GCC!
An interesting discussion is here.
For VC++, here's the test about forward declaration and specifying the underlying type:
The following code is compiled OK.
typedef int myint;
enum T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
enum T : char
{
A
};
But I got the warning for /W4 (/W3 does not incur this warning)
warning C4480: nonstandard extension used: specifying underlying type for enum 'T'
VC++ (Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86) looks buggy in the above case:
when seeing enum T; VC assumes the enum type T uses default 4 bytes int as underlying type, so the generated assembly code is:
?foo##YAXPAW4T###Z PROC ; foo
; File e:\work\c_cpp\cpp_snippet.cpp
; Line 13
push ebp
mov ebp, esp
; Line 14
mov eax, DWORD PTR _tp$[ebp]
mov DWORD PTR [eax], 305419896 ; 12345678H
; Line 15
pop ebp
ret 0
?foo##YAXPAW4T###Z ENDP ; foo
The above assembly code is extracted from /Fatest.asm directly, not my personal guess.
Do you see the
mov DWORD PTR[eax], 305419896 ; 12345678H
line?
the following code snippet proves it:
int main(int argc, char *argv)
{
union {
char ca[4];
T t;
}a;
a.ca[0] = a.ca[1] = a.[ca[2] = a.ca[3] = 1;
foo( &a.t) ;
printf("%#x, %#x, %#x, %#x\n", a.ca[0], a.ca[1], a.ca[2], a.ca[3] );
return 0;
}
The result is:
0x78, 0x56, 0x34, 0x12
After removing the forward declaration of enum T and move the definition of function foo after the enum T's definition: the result is OK:
The above key instruction becomes:
mov BYTE PTR [eax], 120 ; 00000078H
The final result is:
0x78, 0x1, 0x1, 0x1
Note the value is not being overwritten.
So using of the forward-declaration of enum in VC++ is considered harmful.
BTW, to not surprise, the syntax for declaration of the underlying type is same as its in C#. In pratice I found it's worth to save three bytes by specifying the underlying type as char when talking to the embedded system, which is memory limited.
My solution to your problem would be to either:
1 - use int instead of enums: Declare your ints in an anonymous namespace in your CPP file (not in the header):
namespace
{
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
}
As your methods are private, no one will mess with the data. You could even go further to test if someone sends you an invalid data:
namespace
{
const int FUNCTIONALITY_begin = 0 ;
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
const int FUNCTIONALITY_end = 3 ;
bool isFunctionalityCorrect(int i)
{
return (i >= FUNCTIONALITY_begin) && (i < FUNCTIONALITY_end) ;
}
}
2 : create a full class with limited const instantiations, like done in Java. Forward declare the class, and then define it in the CPP file, and instanciate only the enum-like values. I did something like that in C++, and the result was not as satisfying as desired, as it needed some code to simulate an enum (copy construction, operator =, etc.).
3 : As proposed before, use the privately declared enum. Despite the fact an user will see its full definition, it won't be able to use it, nor use the private methods. So you'll usually be able to modify the enum and the content of the existing methods without needing recompiling of code using your class.
My guess would be either the solution 3 or 1.
To anyone facing this for iOS/Mac/Xcode,
If you are facing this while integrating C/C++ headers in XCode with Objective-C, just change the extension of your file from .mm to .m
Because the enum can be an integral size of varying size (the compiler decides which size a given enum has), the pointer to the enum can also have varying size, since it's an integral type (chars have pointers of a different size on some platforms for instance).
So the compiler can't even let you forward-declare the enum and user a pointer to it, because even there, it needs the size of the enum.
You define an enumeration to restrict the possible values of elements of the type to a limited set. This restriction is to be enforced at compile time.
When forward declaring the fact that you will use a 'limited set' later on doesn't add any value: subsequent code needs to know the possible values in order to benefit from it.
Although the compiler is concerned about the size of the enumerated type, the intent of the enumeration gets lost when you forward declare it.
This way we can forward declare enum
enum A : int;
please refer the link for details.

extern enum in c++

I have an enum I have declared in some .h file:
typedef enum {
NONE,
ONE,
TWO,
THREE
} MYENUM;
in a seperate .cpp I cannot do this:
extern enum MYENUM; //works
extern MYENUM TWO; //makes sence, TWO is not an INSTANCE of MYENUM...
how would one do so without including the whole header where the enum is declared?
You can't use an incomplete type. You can only pass around pointers to it. This is because until the type is completed, the compiler doesn't know how big it is. OTOH a pointer is the size of a data pointer, no matter what type it's pointing to. One of the things you can't do with an incomplete type is declare variables of that type.
extern in a variable declaration means that the compiler will emit a reference to an identifier provided in another compilation unit (to be resolved by the linker), instead of allocating storage. extern does not modify the type, even if it appears next to the type name in C++ grammar.
What you can do is take advantage of the fact that enum members are integral constant values, and convert just fine to the primitive integral types.
So you can do this:
A.cpp
enum MYENUM { ONE=1, TWO, THREE };
int var = TWO;
B.cpp
extern int var;
But the types must match. You couldn't say MYENUM var = TWO; and also extern int var;. That would violate the one-definition-rule (violation might or might not be detected by the linker).
As an aside, this is incorrect:
typedef enum {
NONE,
ONE,
TWO,
THREE
} MYENUM;
enum MYENUM TWO;
MYENUM is NOT an enum identifier. It is a typedef, and cannot be qualified with the enum keyword later.
You cannot use enum values, if they are not visible. If the header is too large to include, why not just put the enum in its own header, and include only that?

Forward declaring an enum in C++

I'm trying to do something like the following:
enum E;
void Foo(E e);
enum E {A, B, C};
which the compiler rejects. I've had a quick look on Google and the consensus seems to be "you can't do it", but I can't understand why. Can anyone explain?
Clarification 2: I'm doing this as I have private methods in a class that take said enum, and I do not want the enum's values exposed - so, for example, I do not want anyone to know that E is defined as
enum E {
FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}
as project X is not something I want my users to know about.
So, I wanted to forward declare the enum so I could put the private methods in the header file, declare the enum internally in the cpp, and distribute the built library file and header to people.
As for the compiler - it's GCC.
Forward declaration of enums is possible since C++11. Previously, the reason enum types couldn't be forward declared was because the size of the enumeration depended on its contents. As long as the size of the enumeration is specified by the application, it can be forward declared:
enum Enum1; // Illegal in C++03 and C++11; no size is explicitly specified.
enum Enum2 : unsigned int; // Legal in C++11.
enum class Enum3; // Legal in C++11, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; // Legal C++11.
enum Enum2 : unsigned short; // Illegal in C++11, because Enum2 was previously declared with a different type.
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() 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)
You can forward-declare an enum in C++11, so long as you declare its storage type at the same time. The syntax looks like this:
enum E : short;
void foo(E e);
....
enum E : short
{
VALUE_1,
VALUE_2,
....
}
In fact, if the function never refers to the values of the enumeration, you don't need the complete declaration at all at that point.
This is supported by G++ 4.6 and onwards (-std=c++0x or -std=c++11 in more recent versions). Visual C++ 2013 supports this; in earlier versions it has some sort of non-standard support that I haven't figured out yet - I found some suggestion that a simple forward declaration is legal, but your mileage may vary.
Forward declaring things in C++ is very useful because it dramatically speeds up compilation time. You can forward declare several things in C++ including: struct, class, function, etc...
But can you forward declare an enum in C++?
No, you can't.
But why not allow it? If it were allowed you could define your enum type in your header file, and your enum values in your source file. It sounds like it should be allowed, right?
Wrong.
In C++ there is no default type for enum like there is in C# (int). In C++ your enum type will be determined by the compiler to be any type that will fit the range of values you have for your enum.
What does that mean?
It means that your enum's underlying type cannot be fully determined until you have all of the values of the enum defined. Which means you cannot separate the declaration and definition of your enum. And therefore you cannot forward declare an enum in C++.
The ISO C++ standard S7.2.5:
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 an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof() applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() applied to the underlying type.
You can determine the size of an enumerated type in C++ by using the sizeof operator. The size of the enumerated type is the size of its underlying type. In this way you can guess which type your compiler is using for your enum.
What if you specify the type of your enum explicitly like this:
enum Color : char { Red=0, Green=1, Blue=2};
assert(sizeof Color == 1);
Can you then forward declare your enum?
No. But why not?
Specifying the type of an enum is not actually part of the current C++ standard. It is a VC++ extension. It will be part of C++0x though.
Source
[My answer is wrong, but I've left it here because the comments are useful].
Forward declaring enums is non-standard, because pointers to different enum types are not guaranteed to be the same size. The compiler may need to see the definition to know what size pointers can be used with this type.
In practice, at least on all the popular compilers, pointers to enums are a consistent size. Forward declaration of enums is provided as a language extension by Visual C++, for example.
There is indeed no such thing as a forward declaration of enum. As an enum's definition doesn't contain any code that could depend on other code using the enum, it's usually not a problem to define the enum completely when you're first declaring it.
If the only use of your enum is by private member functions, you can implement encapsulation by having the enum itself as a private member of that class. The enum still has to be fully defined at the point of declaration, that is, within the class definition. However, this is not a bigger problem as declaring private member functions there, and is not a worse exposal of implementation internals than that.
If you need a deeper degree of concealment for your implementation details, you can break it into an abstract interface, only consisting of pure virtual functions, and a concrete, completely concealed, class implementing (inheriting) the interface. Creation of class instances can be handled by a factory or a static member function of the interface. That way, even the real class name, let alone its private functions, won't be exposed.
I am just noting that the reason actually is that the size of the enum is not yet known after forward declaration. Well, you use forward declaration of a struct to be able to pass a pointer around or refer to an object from a place that's referred to in the forward declared struct definition itself too.
Forward declaring an enum would not be too useful, because one would wish to be able to pass around the enum by-value. You couldn't even have a pointer to it, because I recently got told some platforms use pointers of different size for char than for int or long. So it all depends on the content of the enum.
The current C++ Standard explicitly disallows doing something like
enum X;
(in 7.1.5.3/1). But the next C++ Standard due to next year allows the following, which convinced me the problem actually has to do with the underlying type:
enum X : int;
It's known as an "opaque" enum declaration. You can even use X by value in the following code. And its enumerators can later be defined in a later redeclaration of the enumeration. See 7.2 in the current working draft.
I'd do it this way:
[in the public header]
typedef unsigned long E;
void Foo(E e);
[in the internal header]
enum Econtent { FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X,
FORCE_32BIT = 0xFFFFFFFF };
By adding FORCE_32BIT we ensure that Econtent compiles to a long, so it's interchangeable with E.
You can wrap the enum in a struct, adding in some constructors and type conversions, and forward declare the struct instead.
#define ENUM_CLASS(NAME, TYPE, VALUES...) \
struct NAME { \
enum e { VALUES }; \
explicit NAME(TYPE v) : val(v) {} \
NAME(e v) : val(v) {} \
operator e() const { return e(val); } \
private:\
TYPE val; \
}
This appears to work:
http://ideone.com/TYtP2
If you really don't want your enum to appear in your header file and ensure that it is only used by private methods, then one solution can be to go with the PIMPL principle.
It's a technique that ensure to hide the class internals in the headers by just declaring:
class A
{
public:
...
private:
void* pImpl;
};
Then in your implementation file (.cpp), you declare a class that will be the representation of the internals.
class AImpl
{
public:
AImpl(A* pThis): m_pThis(pThis) {}
... all private methods here ...
private:
A* m_pThis;
};
You must dynamically create the implementation in the class constructor and delete it in the destructor and when implementing public method, you must use:
((AImpl*)pImpl)->PrivateMethod();
There are pros for using PIMPL. One is that it decouples your class header from its implementation, and there isn't any need to recompile other classes when changing one class implementation. Another is that is speeds up your compilation time, because your headers are so simple.
But it's a pain to use, so you should really ask yourself if just declaring your enum as private in the header is that much a trouble.
There's some dissent since this got bumped (sort of), so here's some relevant bits from the standard. Research shows that the standard doesn't really define forward declaration, nor does it explicitly state that enums can or can't be forward declared.
First, from dcl.enum, section 7.2:
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 an int or
unsigned int. If the enumerator-list
is empty, the underlying type is as if
the enumeration had a single
enumerator with value 0. The value of
sizeof() applied to an enumeration
type, an object of enumeration type,
or an enumerator, is the value of
sizeof() applied to the underlying
type.
So the underlying type of an enum is implementation-defined, with one minor restriction.
Next we flip to the section on "incomplete types" (3.9), which is about as close as we come to any standard on forward declarations:
A class that has been declared but not defined, or an array of unknown size or of
incomplete element type, is an incompletely-defined object type.
A class type (such as "class X") might be incomplete at one point in a translation
unit and complete later on; the type "class X" is the same type at both points. The
declared type of an array object might be an array of incomplete class type and
therefore incomplete; if the class type is completed later on in the translation unit,
the array type becomes complete; the array type at those two points is the same type.
The declared type of an array object might be an array of unknown size and therefore be
incomplete at one point in a translation unit and complete later on; the array types at
those two points ("array of unknown bound of T" and "array of N T") are different
types. The type of a pointer to array of unknown size, or of a type defined by a typedef
declaration to be an array of unknown size, cannot be completed.
So there, the standard pretty much laid out the types that can be forward declared. Enum wasn't there, so compiler authors generally regard forward declaring as disallowed by the standard due to the variable size of its underlying type.
It makes sense, too. Enums are usually referenced in by-value situations, and the compiler would indeed need to know the storage size in those situations. Since the storage size is implementation defined, many compilers may just choose to use 32 bit values for the underlying type of every enum, at which point it becomes possible to forward declare them.
An interesting experiment might be to try forward declaring an enum in Visual Studio, then forcing it to use an underlying type greater than sizeof(int) as explained above to see what happens.
In my projects, I adopted the Namespace-Bound Enumeration technique to deal with enums from legacy and 3rd-party components. Here is an example:
forward.h:
namespace type
{
class legacy_type;
typedef const legacy_type& type;
}
enum.h:
// May be defined here or pulled in via #include.
namespace legacy
{
enum evil { x , y, z };
}
namespace type
{
using legacy::evil;
class legacy_type
{
public:
legacy_type(evil e)
: e_(e)
{}
operator evil() const
{
return e_;
}
private:
evil e_;
};
}
foo.h:
#include "forward.h"
class foo
{
public:
void f(type::type t);
};
foo.cc:
#include "foo.h"
#include <iostream>
#include "enum.h"
void foo::f(type::type t)
{
switch (t)
{
case legacy::x:
std::cout << "x" << std::endl;
break;
case legacy::y:
std::cout << "y" << std::endl;
break;
case legacy::z:
std::cout << "z" << std::endl;
break;
default:
std::cout << "default" << std::endl;
}
}
main.cc:
#include "foo.h"
#include "enum.h"
int main()
{
foo fu;
fu.f(legacy::x);
return 0;
}
Note that the foo.h header does not have to know anything about legacy::evil. Only the files that use the legacy type legacy::evil (here: main.cc) need to include enum.h.
It seems it can not be forward-declared in GCC!
An interesting discussion is here.
For VC++, here's the test about forward declaration and specifying the underlying type:
The following code is compiled OK.
typedef int myint;
enum T ;
void foo(T * tp )
{
* tp = (T)0x12345678;
}
enum T : char
{
A
};
But I got the warning for /W4 (/W3 does not incur this warning)
warning C4480: nonstandard extension used: specifying underlying type for enum 'T'
VC++ (Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86) looks buggy in the above case:
when seeing enum T; VC assumes the enum type T uses default 4 bytes int as underlying type, so the generated assembly code is:
?foo##YAXPAW4T###Z PROC ; foo
; File e:\work\c_cpp\cpp_snippet.cpp
; Line 13
push ebp
mov ebp, esp
; Line 14
mov eax, DWORD PTR _tp$[ebp]
mov DWORD PTR [eax], 305419896 ; 12345678H
; Line 15
pop ebp
ret 0
?foo##YAXPAW4T###Z ENDP ; foo
The above assembly code is extracted from /Fatest.asm directly, not my personal guess.
Do you see the
mov DWORD PTR[eax], 305419896 ; 12345678H
line?
the following code snippet proves it:
int main(int argc, char *argv)
{
union {
char ca[4];
T t;
}a;
a.ca[0] = a.ca[1] = a.[ca[2] = a.ca[3] = 1;
foo( &a.t) ;
printf("%#x, %#x, %#x, %#x\n", a.ca[0], a.ca[1], a.ca[2], a.ca[3] );
return 0;
}
The result is:
0x78, 0x56, 0x34, 0x12
After removing the forward declaration of enum T and move the definition of function foo after the enum T's definition: the result is OK:
The above key instruction becomes:
mov BYTE PTR [eax], 120 ; 00000078H
The final result is:
0x78, 0x1, 0x1, 0x1
Note the value is not being overwritten.
So using of the forward-declaration of enum in VC++ is considered harmful.
BTW, to not surprise, the syntax for declaration of the underlying type is same as its in C#. In pratice I found it's worth to save three bytes by specifying the underlying type as char when talking to the embedded system, which is memory limited.
My solution to your problem would be to either:
1 - use int instead of enums: Declare your ints in an anonymous namespace in your CPP file (not in the header):
namespace
{
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
}
As your methods are private, no one will mess with the data. You could even go further to test if someone sends you an invalid data:
namespace
{
const int FUNCTIONALITY_begin = 0 ;
const int FUNCTIONALITY_NORMAL = 0 ;
const int FUNCTIONALITY_RESTRICTED = 1 ;
const int FUNCTIONALITY_FOR_PROJECT_X = 2 ;
const int FUNCTIONALITY_end = 3 ;
bool isFunctionalityCorrect(int i)
{
return (i >= FUNCTIONALITY_begin) && (i < FUNCTIONALITY_end) ;
}
}
2 : create a full class with limited const instantiations, like done in Java. Forward declare the class, and then define it in the CPP file, and instanciate only the enum-like values. I did something like that in C++, and the result was not as satisfying as desired, as it needed some code to simulate an enum (copy construction, operator =, etc.).
3 : As proposed before, use the privately declared enum. Despite the fact an user will see its full definition, it won't be able to use it, nor use the private methods. So you'll usually be able to modify the enum and the content of the existing methods without needing recompiling of code using your class.
My guess would be either the solution 3 or 1.
To anyone facing this for iOS/Mac/Xcode,
If you are facing this while integrating C/C++ headers in XCode with Objective-C, just change the extension of your file from .mm to .m
Because the enum can be an integral size of varying size (the compiler decides which size a given enum has), the pointer to the enum can also have varying size, since it's an integral type (chars have pointers of a different size on some platforms for instance).
So the compiler can't even let you forward-declare the enum and user a pointer to it, because even there, it needs the size of the enum.
You define an enumeration to restrict the possible values of elements of the type to a limited set. This restriction is to be enforced at compile time.
When forward declaring the fact that you will use a 'limited set' later on doesn't add any value: subsequent code needs to know the possible values in order to benefit from it.
Although the compiler is concerned about the size of the enumerated type, the intent of the enumeration gets lost when you forward declare it.
This way we can forward declare enum
enum A : int;
please refer the link for details.

Difference between 'struct' and 'typedef struct' in C++?

In C++, is there any difference between:
struct Foo { ... };
and:
typedef struct { ... } Foo;
In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.
The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for struct/union/enum) and ordinary identifiers (for typedef and other identifiers).
If you just said:
struct Foo { ... };
Foo x;
you would get a compiler error, because Foo is only defined in the tag namespace.
You'd have to declare it as:
struct Foo x;
Any time you want to refer to a Foo, you'd always have to call it a struct Foo. This gets annoying fast, so you can add a typedef:
struct Foo { ... };
typedef struct Foo Foo;
Now struct Foo (in the tag namespace) and just plain Foo (in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of type Foo without the struct keyword.
The construct:
typedef struct Foo { ... } Foo;
is just an abbreviation for the declaration and typedef.
Finally,
typedef struct { ... } Foo;
declares an anonymous structure and creates a typedef for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.
In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name. See Michael Burr's answer for the full details.
In this DDJ article, Dan Saks explains one small area where bugs can creep through if you do not typedef your structs (and classes!):
If you want, you can imagine that C++
generates a typedef for every tag
name, such as
typedef class string string;
Unfortunately, this is not entirely
accurate. I wish it were that simple,
but it's not. C++ can't generate such
typedefs for structs, unions, or enums
without introducing incompatibilities
with C.
For example, suppose a C program
declares both a function and a struct
named status:
int status(); struct status;
Again, this may be bad practice, but
it is C. In this program, status (by
itself) refers to the function; struct
status refers to the type.
If C++ did automatically generate
typedefs for tags, then when you
compiled this program as C++, the
compiler would generate:
typedef struct status status;
Unfortunately, this type name would
conflict with the function name, and
the program would not compile. That's
why C++ can't simply generate a
typedef for each tag.
In C++, tags act just like typedef
names, except that a program can
declare an object, function, or
enumerator with the same name and the
same scope as a tag. In that case, the
object, function, or enumerator name
hides the tag name. The program can
refer to the tag name only by using
the keyword class, struct, union, or
enum (as appropriate) in front of the
tag name. A type name consisting of
one of these keywords followed by a
tag is an elaborated-type-specifier.
For instance, struct status and enum
month are elaborated-type-specifiers.
Thus, a C program that contains both:
int status(); struct status;
behaves the same when compiled as C++.
The name status alone refers to the
function. The program can refer to the
type only by using the
elaborated-type-specifier struct
status.
So how does this allow bugs to creep
into programs? Consider the program in
Listing 1. This program defines a
class foo with a default constructor,
and a conversion operator that
converts a foo object to char const *.
The expression
p = foo();
in main should construct a foo object
and apply the conversion operator. The
subsequent output statement
cout << p << '\n';
should display class foo, but it
doesn't. It displays function foo.
This surprising result occurs because
the program includes header lib.h
shown in Listing 2. This header
defines a function also named foo. The
function name foo hides the class name
foo, so the reference to foo in main
refers to the function, not the class.
main can refer to the class only by
using an elaborated-type-specifier, as
in
p = class foo();
The way to avoid such confusion
throughout the program is to add the
following typedef for the class name
foo:
typedef class foo foo;
immediately before or after the class
definition. This typedef causes a
conflict between the type name foo and
the function name foo (from the
library) that will trigger a
compile-time error.
I know of no one who actually writes
these typedefs as a matter of course.
It requires a lot of discipline. Since
the incidence of errors such as the
one in Listing 1 is probably pretty
small, you many never run afoul of
this problem. But if an error in your
software might cause bodily injury,
then you should write the typedefs no
matter how unlikely the error.
I can't imagine why anyone would ever
want to hide a class name with a
function or object name in the same
scope as the class. The hiding rules
in C were a mistake, and they should
not have been extended to classes in
C++. Indeed, you can correct the
mistake, but it requires extra
programming discipline and effort that
should not be necessary.
One more important difference: typedefs cannot be forward declared. So for the typedef option you must #include the file containing the typedef, meaning everything that #includes your .h also includes that file whether it directly needs it or not, and so on. It can definitely impact your build times on larger projects.
Without the typedef, in some cases you can just add a forward declaration of struct Foo; at the top of your .h file, and only #include the struct definition in your .cpp file.
There is a difference, but subtle. Look at it this way: struct Foo introduces a new type. The second one creates an alias called Foo (and not a new type) for an unnamed struct type.
7.1.3 The typedef specifier
1 [...]
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.
8 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration
to be that class type (or enum type) is used to denote the class type (or enum type) for linkage
purposes only (3.5). [ Example:
typedef struct { } *ps, S; // S is the class name for linkage purposes
So, a typedef always is used as an placeholder/synonym for another type.
You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
typedef struct{
int one;
int two;
}myStruct;
A forward declaration like this wont work:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
An important difference between a 'typedef struct' and a 'struct' in C++ is that inline member initialisation in 'typedef structs' will not work.
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
There is no difference in C++, but I believe in C it would allow you to declare instances of the struct Foo without explicitly doing:
struct Foo bar;
Struct is to create a data type.
The typedef is to set a nickname for a data type.