当前位置:  开发笔记 > 编程语言 > 正文

转发在C++中声明一个枚举

如何解决《转发在C++中声明一个枚举》经验,为你挑选了7个好方法。

我正在尝试做类似以下的事情:

enum E;

void Foo(E e);

enum E {A, B, C};

编译器拒绝的.我已经快速浏览了一下Google,而且共识似乎是"你做不到",但我无法理解为什么.谁能解释一下?

澄清2:我这样做是因为我在类中使用私有方法来获取枚举,并且我不希望枚举枚举值 - 例如,我不希望任何人知道E被定义为

enum E {
    FUNCTIONALITY_NORMAL, FUNCTIONALITY_RESTRICTED, FUNCTIONALITY_FOR_PROJECT_X
}

因为项目X不是我希望用户了解的东西.

所以,我想转发声明枚举,以便我可以将私有方法放在头文件中,在cpp内部声明枚举,并将构建的库文件和标题分发给人.

至于编译器 - 它是GCC.



1> KJAWolf..:

无法向前声明枚举的原因是,在不知道值的情况下,编译器无法知道枚举变量所需的存储.允许C++编译器根据包含指定的所有值所需的大小来指定实际存储空间.如果所有可见的是前向声明,则翻译单元无法知道将选择哪种存储大小 - 它可以是char或int,或其他.


从ISO C++标准的第7.2.5节:

枚举的基础类型是一个整数类型,可以表示枚举中定义的所有枚举器值.它是实现定义的,其中整数类型用作枚举的基础类型,除了基础类型不应大于int枚举器的值不能适合于intunsigned int.如果枚举器列表为空,则基础类型就好像枚举具有值为0的单个枚举器.sizeof()应用于枚举类型,枚举类型的对象或枚举器的值是sizeof()应用于基础类型.

由于函数的调用者必须知道参数的大小才能正确设置调用堆栈,因此在函数原型之前必须知道枚举列表中的枚举数.

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


@j_random:在完全定义之前不能使用类 - 您只能使用指针或对该类的引用,因为它们的大小和操作方式不依赖于类.
-1.你的推理不可能是正确的 - 否则,为什么你被允许向前宣布"C级"; 然后在完全定义C之前声明一个获取或返回C的函数原型?
引用或指向类对象的指针的大小由编译器设置,并且与对象的实际大小无关 - 它是指针和引用的大小.枚举是一个对象,编译器需要其大小才能访问正确的存储.
我知道这个讨论很久以前就结束了,但是我必须在这里与@j_random_hacker对齐:这里的问题不是关于指针或对不完整类型的引用,而是关于在声明中使用不完整类型.因为`struct S是合法的; void foo(S s);`(注意`foo`只是声明,没有定义),那么就没有理由我们不能做`enum E; void foo(E e);`也是.在这两种情况下,都不需要大小.
从逻辑上讲,如果我们有前向声明的枚举,就可以声明指向枚举的引用/引用,就像我们可以用类做的那样.只是你不经常处理枚举指针:)
这不是挑剔 - 整个讨论的主题是在函数原型中使用类前向定义.j_random_hacker说你可以做到,RnR说你做不到 - 他错了.
谢谢@Luc.也许我有点粗暴,得知结构S是一个惊喜; void foo(S s);`是合法的C++,因为`struct S; void foo(S s){}`不是(在这种情况下必须定义`S`).但似乎大多数人都没有注意到声明/定义的区别.
我知道这是一个古老的讨论,但我想再次强调,尽管有很多人投票给他,但@RnR在很大程度上是错误的 - 在某些情况下完全定义之前使用类是完全合法的,包括作为函数的参数或从函数返回值.如果你不相信我,试试吧 - 声明一个`A类;`和一个`void foo(A);`,然后提供两者的实现,看它是否编译.
我的观点是,在声明函数原型时,编译器不需要知道参数的大小,无论它是类还是枚举.显然,能够在这里指定不完整​​的类类型是有用的,这很好 - 所以为什么不是不完整的枚举类型?
@Tom-我认为声明不是_使用_一个类;而取消引用或访问类中的字段则是。+1为RnR;)
@nevelis - RnR所说的是"你只能使用指针或对该类的引用",这根本不是真的,错误,错误.
** - 1**重新启动"由于函数的调用者必须知道参数的大小才能正确设置调用堆栈,因此在函数原型之前必须知道枚举列表中的枚举数."不.通过值参数以及函数结果在原型中可以是不完整的类型.在定义或调用中,它们必须是已知的,但不能在原型中.

2> 小智..:

在C++ 0x中也可以进行枚举的前向声明.以前,枚举类型无法向前声明的原因是因为枚举的大小取决于其内容.只要枚举的大小由应用程序指定,就可以向前声明:

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.


@rubenvb Visual C++ 11(2012)http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx

3> Tom..:

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

您可以在C++ 11中转发声明枚举,只要您同时声明其存储类型即可.语法如下所示:

enum E : short;
void foo(E e);

....

enum E : short
{
    VALUE_1,
    VALUE_2,
    ....
}

实际上,如果函数永远不会引用枚举的值,那么此时您根本不需要完整的声明.

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


+1因为这是唯一提到您需要在声明中声明类型以及定义的答案.

4> Brian R. Bon..:

使用C++声明事物非常有用,因为它可以大大加快编译时间.你可以把用C宣布几件事情++包括:struct,class,function,等...

但是你可以enum在C++中转发声明吗?

不,你不能.

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

错误.

在C++中,没有enum类似C#(int)中的默认类型.在C++中,您的enum类型将由编译器确定为适合您的值范围的任何类型enum.

那是什么意思?

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

ISO C++标准S7.2.5:

枚举的基础类型是一个整数类型,可以表示枚举中定义的所有枚举器值.它是实现定义的,其中整数类型用作枚举的基础类型,除了基础类型不应大于int枚举器的值不能适合于intunsigned int.如果枚举器列表为空,则基础类型就好像枚举具有值为0的单个枚举器.sizeof()应用于枚举类型,枚举类型的对象或枚举器的值是sizeof()应用于基础类型.

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

如果您明确指定明确的类型,该怎么办enum:

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

你能转发申报enum吗?

不,但为什么不呢?

指定a的类型enum实际上不是当前C++标准的一部分.它是VC++扩展.它将成为C++ 0x的一部分.

资源


这个答案现在已经过时了几年.

5> James Hopkin..:

[我的回答是错的,但我把它留在这里,因为评论很有用].

前向声明枚举是非标准的,因为指向不同枚举类型的指针不能保证大小相同.编译器可能需要查看定义以了解可以使用此类型的大小指针.

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


+1.推理是正确的.具体情况是sizeof(char*)> sizeof(int*)的平台.两者都可以是枚举的基础类型,具体取决于范围.类没有底层类型,因此类比是错误的.
指向数据的指针和指向函数的指针可以有不同的大小,但我相当确定数据指针必须往返(转换为另一个数据指针类型,然后回到原始,需要仍然工作),这意味着所有数据指针大小相同.
-1.如果你的推理是正确的,同样的推理意味着类类型的前向声明不能用于创建指向这些类型的指针 - 但它们可以.
@MSalters:示例:"struct S {int x;};" 现在,sizeof(S*)*必须*等于任何其他指向结构的指针的大小,因为C++允许在定义S之前声明和使用这样的指针...

6> Alexey Feldg..:

确实没有枚举的前瞻性声明.由于枚举的定义不包含任何可能依赖于使用枚举的其他代码的代码,因此在首次声明时完全定义枚举通常不是问题.

如果枚举的唯一用途是私有成员函数,则可以通过将枚举本身作为该类的私有成员来实现封装.枚举仍然必须在声明点完全定义,即在类定义中.然而,这不是一个更大的问题,因为在那里声明私有成员函数,并不是更糟糕的实现内部的暴露.

如果您需要对实现细节进行更深入的隐藏,可以将其分解为抽象接口,仅包含纯虚函数,以及实现(继承)接口的具体,完全隐藏的类.类实例的创建可以由工厂或接口的静态成员函数处理.这样,即使是真正的类名,更不用说它的私有函数了,也不会暴露出来.



7> Johannes Sch..:

只是指出原因实际上在向前声明后还不知道枚举的大小。好吧,您可以使用结构的前向声明来传递指针或从前向声明的结构定义本身所引用的位置引用对象。

向前声明枚举不会太有用,因为人们希望能够传递枚举值。您甚至都没有指向它的指针,因为最近我被告知某些平台对char使用与int或long不同的大小的指针。因此,这完全取决于枚举的内容。

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

enum X;

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

enum X : int;

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

推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有