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

fed*_*ino 10 c++ c++11

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

如果枚举键之后是嵌套名称说明符,则枚举说明符应引用先前在嵌套名称说明符所引用的类或命名空间中直接声明的枚举(即,既不继承也不引入通过using-declaration),enum-specifier应出现在包含前一个声明的命名空间中.

在7.2,第4段.例如,这禁止转发声明在类中定义的枚举:

struct S{
  enum foo{A, B};
};
Run Code Online (Sandbox Code Playgroud)

现在,S可以向前宣布,而S::foo不是.

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

sky*_*ack 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> {};
Run Code Online (Sandbox Code Playgroud)

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


也就是说,即使您处理命名空间,也无法执行此操作:

struct X::A;
namespace X { struct A {}; }
Run Code Online (Sandbox Code Playgroud)

但你可以这样做:

namespace X { struct A; }
namespace X { struct A {}; }
Run Code Online (Sandbox Code Playgroud)

使用类将产生如下代码:

struct A { enum E; };
struct A { enum E {} };
Run Code Online (Sandbox Code Playgroud)

无论如何,这会违反风险并且不允许.


现在,我会试着告诉你我为什么这么做的印象.
如果允许该类型的前向声明,则允许您给出包含类的部分定义.
换句话说,考虑一下:enum S::E.这坚定地说S 包含枚举类E,因此你给出了关于定义的线索S.要说话不standardese(即远未我自然语言),你被部分定义S,因此编译器应该知道,S有其定义的地方加上它必须有一个定义E过(无论是作为主定义的一部分或作为out一流的定义).
当实际定义进入视图时,这将破坏odr规则,因此在任何情况下都不允许,但作为语言基本规则的例外.
而且,这是头痛的重要原因.

我的两分钱.