为什么不能转发声明范围的枚举?

时间:2016-10-05 09:51:57

标签: c++ c++11

标题已经是问题了 更多细节:标准制定:

  

如果enum-key后跟一个嵌套名称说明符,那么enum-specifier应引用一个枚举   先前已在嵌套名称说明符引用的类或命名空间中直接声明(即,   既不继承也不由using声明引入,并且枚举说明符应出现在命名空间中   附上先前的声明。

见第7.2段第4段。 例如,这禁止前向声明在类中定义的枚举:

struct S{
  enum foo{A, B};
};

现在,S可以向前声明,而S::foo则不能。

问题是关于为什么。是否存在这种规则可以带来好处的情况?为什么需要它?或者,如果您愿意:如果标准没有此规则,是否存在编译器出现问题的情况?哪一个?

3 个答案:

答案 0 :(得分:6)

至少,如果允许转发声明一个枚举,它会产生模板特化问题,如下例所示:

// somewhere in a .cpp

template<typename>
struct S;

enum S<int>::E;

// somewhere in a galaxy far, far away

template<typename>
struct S { enum class E {}; };

template<>
struct S<int> {};

编译器如何知道(并验证)实际定义了enum S<int>::E;

也就是说,即使你处理命名空间,也不能这样做:

struct X::A;
namespace X { struct A {}; }

但你可以这样做:

namespace X { struct A; }
namespace X { struct A {}; }

使用类会产生如下代码:

struct A { enum E; };
struct A { enum E {} };

无论如何,这会违反风险而且不允许。

现在,我会尝试给你关于为什么的印象 如果允许该类型的前向声明,则可以允许您提供包含类的部分定义
换句话说,请考虑这一点:enum S::E。这坚定地表明S 包含枚举类E,因此您可以提供有关S定义的线索。要不在标准中说话(这远非我的自然语言),您部分定义S,因此编译器应该知道S在某处的定义加上它也必须有E的定义(作为主要定义的一部分或作为类外定义)。
当实际定义进入视图时,这将打破odr规则,因此在任何情况下都不允许这样做,但作为语言基本规则的例外。
而且,这是令人头痛的重要原因。

我的两分钱。

答案 1 :(得分:3)

范围enum声明为enum class(或enum struct,而不是struct { enum …。这将是一个无范围的枚举,在类的范围内。

struct S {
    enum foo {A, B}; // Not a scoped enumeration.
};

作用域枚举可以在类中进行前向声明,并在外部定义:

struct S {
    enum class foo;
};

enum class S::foo { A, B };

但是,您不能在类外声明类成员,除非它已经声明并且您正在定义它。允许外部成员声明将违反class { }定义声明所有类成员,C ++类已关闭的原则。&#34;

换句话说,声明和定义成员作用域枚举的规则与成员函数或成员类的规则基本相同。

答案 2 :(得分:0)

enum Enumeration;枚举被不允许转发到头文件中。

enum class Enumeration;枚举类允许在头文件中转发声明。