空的,未命名的枚举说明符的合法性

时间:2015-04-03 13:38:07

标签: c++ c++11 language-lawyer c++14

在§7.5(C ++ 14)的例子中,人们发现:

enum {}; // ill-formed

但是,从技术上讲,我认为代码是有效的。enum {}枚举说明符,因此,它是类型说明符,是一个 decl-specifier ,因此,它是一个 simple-declaration ,省略了 init-declarator-list 。这被§7.5接受。请注意,标识符对于未作用域的枚举是可选的。此外,clang将其编译为警告。

修改

关于提到the *decl-specifier-seq* shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration的答案,我在下面显示了编译的 typedef 声明,但其 decl-specifier-seq 未引入声明中的任何名称:

typedef class {} A;

3 个答案:

答案 0 :(得分:7)

在C ++ 14 FD,正上方您的示例中,解释了为什么声明格式不正确:

  

simple-declaration 中,可选的 init-declarator-list 可以是   仅在声明类(第9条)或枚举(7.2)时省略   [...]

     

在这种情况下, decl-specifier-seq 应引入一个或多个   在程序中输入名称,或者重新声明由a引入的名称   先前的声明。

因此

enum {} e;
enum {a};

Are valid - 我们的引用不适用于第一个声明,因为它包含 init-declarator ,第二个引用名称a作为枚举器。请注意,GCC不会编译第一个声明,这可能是一个错误。

您还提到了引用

  

如果枚举器列表为空,则基础类型就像是   枚举有一个值为0的枚举器。

这是关于基础类型的声明,而不是枚举本身,因此与此事无关。


为什么typedef class {} A;会编译?

A init-declarator 。是的,它是 - [dcl.dcl] / 9:

  

如果 decl-specifier-seq 包含 typedef说明符,   声明称为typedef声明和每个声明的名称    init-declarator 被声明为 typedef-name

即。根据此定义,声明为 typedef-names 的名称是 init-declarators 。因此,有一个 init-declarator-list ,我们的上述引用并不适用。

答案 1 :(得分:2)

标准中有明确的(7声明)

  
      
  1. ...在这种情况下,除了声明未命名的位域(9.6)之外,decl-specifier-seq 应引入一个或多个   名称进入程序,或者重新声明由a引入的名称   先前的声明。
  2.   

此声明

enum {};   // ill-formed 

不符合要求。它没有在程序中引入任何名称。

至于typedef然后

  

7.1.3 typedef说明符1包含可在以后使用的decl-specifier typedef声明标识符的声明   用于命名94)

答案 2 :(得分:2)

如果你仔细研究这个标准,你会发现很多东西会在纯粹的语法层面上被接受,但是被文本禁止。这只是该基本思想的许多实例之一。

其中许多情况非常明显。让我们考虑一个非常微不足道的问题:一个浮点数。使用类似于标准的句法符号,我们可以得到类似的东西:

" - " opt 数字 opt "。&# 34; opt 数字 opt (" e"" - &#34 ; opt 数字) opt

那里的一切都是"可选的"。然而,这并不意味着虚无应该被视为一个数字。也不意味着(例如).e是有效的浮点数。这意味着如果存在其他一些,几乎任何单件都可以省略。你不需要在小数点之后的之前的数字,所以每个都是可选的 - 但是必须存在一个或另一个,所以1.和{{ 1}}都有效,但只有.1不是。同样,.也是可选的 - 类似.的内容是完全有效的浮点文字,即使它在任何地方都不包含1e50

这些限制在与句法符号本身相关的文本中表达。允许(或不允许)的所有内容必须基于所有内容,而不仅仅是单独的内容。