【问题标题】:Point of declaration for an enumeration枚举声明点
【发布时间】:2016-02-29 08:40:48
【问题描述】:

枚举类型声明的意义何在?它是否紧跟在枚举名称之后?我看到了标准 C++ 14 (n4296) §3.3.2/3:

枚举的声明点紧跟在 枚举说明符(7.2)或其第一个中的标识符(如果有) opaque-enum-declaration (7.2),以先到者为准

但是当我尝试复制它时;

template <class T>
struct CL
{
    using UndType = int;
};

enum class E: CL<E>::UndType;  //error: E is undefined

我在所有编译器上都遇到了错误,尽管用于枚举 Eenum-base 放在标识符之后并且必须可见。

【问题讨论】:

  • 我会说它位于 opaque-enum-declaration;// error 之前)。
  • 所以在CL&lt;E&gt;E 确实还没有声明:(
  • Jarod42,但是为什么还没有声明呢?标准说它紧跟在标识符之后,不是吗?没看懂
  • @Jarod42 语法是enum-key attribute-specifier-seq identifier enum-base,所以OP中的引用中提到的identifier在这种情况下似乎是E,不是吗?您示例中的 identifier 不是 enum-specifier 的一部分。
  • 我发现了一个缺陷报告:open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1482。因此,在 enum-base(即 ":CL::UndType")中,枚举 E 必须已经被声明并且是一个不完整的类型

标签: c++ c++11 enums declaration c++14


【解决方案1】:

以下;

enum class E : CL<E>::UndType;

在某些当前实现(测试过的 clang++、g++ 和 MSVC)中不被接受为有效声明。他们不接受 enum-base CL&lt;E&gt;::UndType 中尚未完成的类型 E。测试实现中给出的错误是 E 在此时 未声明。他们似乎将声明点放在 enum-base 的末尾,他们认为它一旦完成就声明了。

阅读规范时;

§14.3.1/2 模板类型参数

[ 注意:模板类型参数可能是不完整的类型(3.9)。 ——尾注]

还有

§7.2/6 枚举声明

其基础类型固定的枚举从其声明点 (3.3.2) 到紧随其枚举基础(如果有)之后是不完整类型,此时它成为完整类型。

是否暗示它是可编译的;与 CRTP 实现一样。

我注意到这(即无法编译enum class E : CL&lt;E&gt;::UndType;)是否是意图,或者它是否被视为一个用例。从规范中,不透明的枚举声明被给予了一些“特殊”的处理w.r.t。它的基类型以及它必须是整数类型的要求。

假设解析为CWG#1482,代码应该是可编译的


至于目前的解决方法...

这个;

enum class E; // default underlying type is int

是最小的声明。

不透明的声明可以是;

enum class E : int; // int base

以下是完整的定义(包括枚举数);

enum class E : int {/*...*/};

或者要使用类模板,可以使用其他类型(可能是void)。

enum class E : CL<void>::UndType;

【讨论】:

  • 来自en.cppreference.com/w/cpp/language/enum,底层类型是声明的一部分。 enum class E 仅相当于 enum class E : int。将UndType 更改为char 甚至会产生错误Demo
  • 现在好多了,但是关于 enum-base “尚未完成”的部分仍然不对。这是int 的别名,仅此而已;当 CL&lt;E&gt; 被隐式实例化时,E 确实不完整的事实在这种情况下是无关紧要的。
  • @bogdan。正确,我认为这是问题的症结所在,实现并不认为它是完整的——我认为我需要以某种方式重新编写该部分。可能类似于“他们不接受基础 CL&lt;E&gt;::UndType 中尚不完整的 E 类型。”?
  • 他们并没有抱怨它不完整。我看到的所有错误消息都报告说E 是一个未声明的标识符。这表明他们只是将声明点放在 enum-base 之后,根据 OP 中的引用,这是不正确的。
  • @bogdan。正确,我相信他们的错误是他们只在这种情况下完成后才将类型标记为已声明。
【解决方案2】:

现在CWG2516 已为此打开。

我认为这是标准中的一个错误,它禁止is_scoped_enum 的可移植实现。

【讨论】: