在 C++ 中前向声明枚举

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/71416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:38:24  来源:igfitidea点击:

Forward declaring an enum in C++

c++enums

提问by szevvy

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

说明 2:我这样做是因为我在一个采用上述枚举的类中有私有方法,并且我不希望暴露枚举的值 - 例如,我不希望任何人知道 E 被定义为

enum E {
    FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}

as project X is not something I want my users to know about.

因为项目 X 不是我想让我的用户知道的东西。

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.

所以,我想转发声明枚举,这样我就可以将私有方法放在头文件中,在 cpp 内部声明枚举,并将构建的库文件和头文件分发给人们。

As for the compiler - it's GCC.

至于编译器 - 它是 GCC。

采纳答案by KJAWolf

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++ Compiler's 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 will have been chosen - it could be a char or an int, or something else.

枚举不能前向声明的原因是,如果不知道值,编译器就无法知道枚举变量所需的存储空间。C++ 编译器可以根据包含所有指定值所需的大小来指定实际存储空间。如果所有可见的是前向声明,则翻译单元无法知道将选择什么存储大小 - 它可以是 char 或 int,或其他东西。



From Section 7.2.5 of the ISO C++ Standard:

来自 ISO C++ 标准的第 7.2.5 节:

The underlying typeof 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 intunless the value of an enumerator cannot fit in an intor unsigned int. If the enumerator-listis 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.

枚举的基础类型是可以表示枚举中定义的所有枚举器值的整数类型。将哪种整数类型用作枚举的基础类型是实现定义的,除非基础类型不得大于 ,int除非枚举数的值不能放入int或 中unsigned int。如果枚举器列表为空,则底层类型就好像枚举具有单个值为 0sizeof()的枚举器。应用于枚举类型、枚举类型对象或枚举器的值是sizeof()应用于底层类型。

Since the callerto the function must know the sizes of the parameters to correctly setup 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 foreward declaring enum types has been proposed and accepted. You can see the proposal at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf

更新:在 C++0X 中,已经提出并接受了用于预先声明枚举类型的语法。您可以在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf 上查看该提案

回答by user119017

Forward declaration of enums is possible since C++11. Previously, the reason enum types couldn't be forward declared is because the size of the enumeration depends on its contents. As long as the size of the enumeration is specified by the application, it can be forward declared:

从 C++11 开始,枚举的前向声明是可能的。以前,无法前向声明枚举类型的原因是枚举的大小取决于其内容。只要应用程序指定了枚举的大小,就可以向前声明:

enum Enum1;                   //Illegal in C++ and C++0x; no size is explicitly specified.
enum Enum2 : unsigned int;    //Legal in C++0x.
enum class Enum3;             //Legal in C++0x, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; //Legal C++0x.
enum Enum2 : unsigned short;  //Illegal in C++0x, because Enum2 was previously declared with a different type.

回答by Tom

I'm adding an up-to-date answer here, given recent developments.

鉴于最近的事态发展,我在这里添加了一个最新的答案。

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:

你可以在 C++11 中前向声明一个枚举,只要你同时声明它的存储类型。语法如下所示:

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++0xor -std=c++11in 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 YMMV.

G++ 4.6 及更高版本(-std=c++0x-std=c++11更新的版本)支持此功能。Visual C++ 2013 支持这一点;在早期版本中,它具有某种我尚未弄清楚的非标准支持 - 我发现一些建议,即简单的前向声明是合法的,但是 YMMV。

回答by Brian R. Bondy

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...

C++ 中的前向声明非常有用,因为它极大地加快了编译时间。您可以向前声明用C几件事情++包括:structclassfunction,等...

But can you forward declare an enumin C++?

但是你能enum在 C++ 中向前声明 an吗?

No you can't.

不,你不能。

But why not allow it? If it were allowed you could define your enumtype in your header file, and your enumvalues in your source file. Sounds like it should be allowed right?

但为什么不允许呢?如果允许,您可以enum在头文件中定义类型,enum在源文件中定义值。听起来应该允许吧?

Wrong.

错误的。

In C++ there is no default type for enumlike there is in C# (int). In C++ your enumtype will be determined by the compiler to be any type that will fit the range of values you have for your enum.

在 C++ 中,没有enum像 C# (int) 中那样的默认类型。在 C++ 中,您的enum类型将由编译器确定为适合您的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 enumdefined. Which mans you cannot separate the declaration and definition of your enum. And therefore you cannot forward declare an enumin C++.

这意味着enum在您拥有enum定义的所有值之前,无法完全确定您的基础类型。哪个男人你不能分开你的enum. 因此你不能enum在 C++ 中向前声明 an 。

The ISO C++ standard S7.2.5:

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 intunless the value of an enumerator cannot fit in an intor 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.

枚举的基础类型是可以表示枚举中定义的所有枚举器值的整数类型。将哪种整数类型用作枚举的基础类型是实现定义的,除非基础类型不得大于 ,int除非枚举数的值不能放入int或 中unsigned int。如果枚举器列表为空,则底层类型就好像枚举具有单个值为 0sizeof()的枚举器。应用于枚举类型、枚举类型对象或枚举器的值是sizeof()应用于底层类型。

You can determine the size of an enumerated type in C++ by using the sizeofoperator. 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.

您可以使用sizeof运算符确定 C++ 中枚举类型的大小。枚举类型的大小是其基础类型的大小。通过这种方式,您可以猜测您的编译器为您的enum.

What if you specify the type of your enumexplicitly like this:

如果您enum像这样明确指定类型会怎样:

enum Color : char { Red=0, Green=1, Blue=2};
assert(sizeof Color == 1);

Can you then forward declare your enum?

然后你可以转发声明你的enum?

No. But why not?

不,但为什么不呢?

Specifying the type of an enumis not actually part of the current C++ standard. It is a VC++ extension. It will be part of C++0x though.

指定 an 的类型enum实际上并不是当前 C++ 标准的一部分。它是一个 VC++ 扩展。不过,它将成为 C++0x 的一部分。

Source

来源

回答by James Hopkin

[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.

实际上,至少在所有流行的编译器上,指向枚举的指针的大小是一致的。例如,枚举的前向声明作为语言扩展由 Visual C++ 提供。

回答by Alexey Feldgendler

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.

如果你需要对你的实现细节进行更深层次的隐藏,你可以把它分解成一个抽象接口,只包含纯虚函数,和一个具体的、完全隐藏的、实现(继承)接口的类。类实例的创建可以由接口的工厂或静态成员函数处理。这样,即使是真正的类名,更不用说它的私有函数,也不会暴露。

回答by Johannes Schaub - litb

Just noting that the reason actually isthat 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 refered 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.

向前声明枚举不会太有用,因为人们希望能够按值传递枚举。你甚至不能有一个指向它的指针,因为我最近被告知一些平台对 char 使用不同大小的指针,而不是 int 或 long。所以这一切都取决于枚举的内容。

The current C++ Standard explicitly disallows doing something like

当前的 C++ 标准明确禁止做类似的事情

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 hasto do with the underlying type:

(在7.1.5.3/1)。但接下来的C ++标准,由于明年允许以下,这使我确信实际问题具有与基本型的事:

enum X : int;

It's known as a "opaque" enum declaration. You can even use X by valuein the following code. And its enumerators can later be defined in a later redeclaration of the enumeration. See 7.2in the current working draft.

它被称为“不透明”枚举声明。您甚至可以在以下代码中按值使用 X。它的枚举器稍后可以在枚举的稍后重新声明中定义。参见7.2当前工作草案。

回答by Laurie Cheers

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.

通过添加 FORCE_32BIT,我们确保 Econtent 编译为 long,因此它可以与 E 互换。

回答by Vincent Robert

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.

如果您真的不希望您的 enum 出现在您的头文件中并确保它仅被私有方法使用,那么一种解决方案是使用 pimpl 原则。

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.

然后在您的实现文件 (cpp) 中,您声明一个将作为内部表示的类。

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 decouple your class header from its implementation, no 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.

使用 pimpl 有一些优点,一是它将类头与其实现解耦,更改一个类实现时无需重新编译其他类。另一个是加快编译时间,因为您的标头非常简单。

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.

但是使用起来很痛苦,所以你真的应该问问自己,在标题中将你的枚举声明为私有是否有那么大的麻烦。

回答by Leszek Swirski

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

这似乎有效:http: //ideone.com/TYtP2