我想做的事情如下:
enum E;
void Foo(E e);
enum E {A, B, C};
编译器拒绝它。我在谷歌上快速浏览了一下,共识似乎是“你做不到”,但我不明白为什么。有人能解释一下吗?
澄清2:我这样做是因为我在一个类中有私有方法,它采用所说的枚举,我不希望枚举的值暴露出来-因此,例如,我不希望任何人知道E被定义为
enum E {
FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}
项目X不是我想让我的用户知道的东西。
所以,我想要转发声明枚举,这样我就可以把私有方法放在头文件中,在cpp中内部声明枚举,并将构建的库文件和头分发给人们。
至于编译器——它是GCC。
如果您真的不希望枚举出现在头文件中,并确保它只被私有方法使用,那么一种解决方案是遵循PIMPL原则。
这是一种确保在头文件中隐藏类内部信息的技术,只需声明:
class A
{
public:
...
private:
void* pImpl;
};
然后在实现文件(.cpp)中声明一个类,该类将作为内部结构的表示。
class AImpl
{
public:
AImpl(A* pThis): m_pThis(pThis) {}
... all private methods here ...
private:
A* m_pThis;
};
你必须在类构造函数中动态创建实现,并在析构函数中删除它,当实现公共方法时,你必须使用:
((AImpl*)pImpl)->PrivateMethod();
使用PIMPL有优点。一个是它将类头与其实现解耦,并且在更改一个类实现时不需要重新编译其他类。另一个原因是加快了你的编译时间,因为你的头文件太简单了。
但它使用起来很痛苦,所以你应该问问自己,仅仅在头文件中将枚举声明为private是否有那么大的麻烦。
enum不能被前向声明的原因是,如果不知道值,编译器就不能知道enum变量所需的存储空间。c++编译器可以根据包含所有指定值所需的大小指定实际存储空间。如果所有可见的都是前向声明,那么翻译单元就不能知道所选择的存储大小是什么——它可能是char型、int型或其他类型。
ISO c++标准第7.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.
由于函数的调用者必须知道参数的大小才能正确地设置调用堆栈,因此枚举列表中的枚举数必须在函数原型之前知道。
更新:
在c++ 0X中,已经提出并接受了向前声明enum类型的语法。你可参阅前向申报枚举数(修订版3)的建议
如果您真的不希望枚举出现在头文件中,并确保它只被私有方法使用,那么一种解决方案是遵循PIMPL原则。
这是一种确保在头文件中隐藏类内部信息的技术,只需声明:
class A
{
public:
...
private:
void* pImpl;
};
然后在实现文件(.cpp)中声明一个类,该类将作为内部结构的表示。
class AImpl
{
public:
AImpl(A* pThis): m_pThis(pThis) {}
... all private methods here ...
private:
A* m_pThis;
};
你必须在类构造函数中动态创建实现,并在析构函数中删除它,当实现公共方法时,你必须使用:
((AImpl*)pImpl)->PrivateMethod();
使用PIMPL有优点。一个是它将类头与其实现解耦,并且在更改一个类实现时不需要重新编译其他类。另一个原因是加快了你的编译时间,因为你的头文件太简单了。
但它使用起来很痛苦,所以你应该问问自己,仅仅在头文件中将枚举声明为private是否有那么大的麻烦。
在c++中向前声明是非常有用的,因为它极大地加快了编译时间。你可以在c++中前向声明一些东西,包括:结构,类,函数,等等…
但是你能在c++中前向声明一个枚举吗?
不,你不能。
但为什么不允许呢?如果允许的话,你可以在头文件中定义枚举类型,在源文件中定义枚举值。听起来应该是允许的,对吧?
错了。
在c++中,没有像c# (int)中那样的enum默认类型。在c++中,你的枚举类型将由编译器决定为适合你的枚举值范围的任何类型。
这是什么意思?
这意味着在定义了枚举的所有值之前,不能完全确定枚举的底层类型。这意味着您不能将枚举的声明和定义分开。因此,在c++中不能前向声明枚举。
ISO c++标准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.
在c++中,可以使用sizeof操作符确定枚举类型的大小。枚举类型的大小是其基础类型的大小。通过这种方式,您可以猜测编译器正在为枚举使用哪种类型。
如果你像这样显式地指定枚举的类型会怎样:
enum Color : char { Red=0, Green=1, Blue=2};
assert(sizeof Color == 1);
然后你可以向前声明你的枚举吗?
不。但为什么不呢?
指定枚举的类型实际上不是当前c++标准的一部分。它是一个vc++扩展。不过,它将成为c++ 0x的一部分。
源