とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

変数宣言でenumを省略できる理由

列挙型の続き。

コメント欄
anony 2011/01/10 00:05 enumのtypedefの件ですが、typedefじゃ無いのは何故でしょう?
私は柴田望洋さんの入門書で構造体形式の記述は暗黙のtypedefが
行われているとの記述からで、それをずっと引きずってますが。

簡単な答え

「typedefされている」とは規格に書かれていないから。どこかに書いてあったら教えてください。規格に書かれていないのでしたら、そう書いてある本が間違っています。

詳細な答え

文法(構文規則)を見る

JISX3014:2003(ISO/IEC 14882:2003)を元に構文規則を確認してみましょう。正確な構文規則は最後に引用します。
「宣言」→「ブロック宣言」→「単純宣言」→「宣言指定子列」→「宣言子」→「型指定子」ここまでたどると次から分岐します。
「単純型指定子」へ進むと→「型名」→「列挙体名」→「識別子」となり、この「識別子」とは

列挙体指定子:
        enum 識別子opt { 列挙子並びopt }

で表れる識別子のことで、この経路だと enum は表れません。
一方「詳述型指定子」へ進むと

        enum ::opt 入れ子名前指定子opt 識別子

となり enum が表れます。
このように構文規則で複数の経路が定められているからこそenumを省略できることが分かります。typedefは関係ありません。

歴史を見る

C++の設計と進化のP056 2.8.2 構造体タグとタイプ名 が興味深いです。

 struct buffer a; /* Cでは'struct'が必要 */

C with Classesでは、これがずっと悩みの種だった。なぜかというとこのルールは、ユーザ定義タイプに対するシンタクス的差別だからだ。(snip)ユーザ定義タイプ(struct, union, class)の変数や定数の名前を、単純にこう書けるように変えることができた:

 buffer a // C++

どういうわけか文章中では悲しいことにenumが含められていませんが、enumもユーザ定義タイプでしょうからenumの省略は同じ理由だと思います。(根拠弱しw)

おまけ

正確な構文規則

7. 宣言 宣言は,名前をどう解釈すべきかを指定する。宣言の形式は,次のとおりとする。
宣言列:
        宣言
        宣言列 宣言
宣言:
        ブロック宣言
        関数定義
        テンプレート宣言
        明示的具現化
        明示的特殊化
        結合指定
        名前空間定義
ブロック宣言:
        単純宣言
        asm定義
        名前空間別名定義
        using宣言
        using指令

単純宣言:
        宣言指定子列opt 初期化宣言子並びopt ;

7.1 指定子 《宣言》の中で使える指定子は,次のとおりとする。
宣言指定子:
        記憶域種別指定子
        型指定子
        関数指定子
        friend
        typedef

宣言指定子列:
        宣言指定子列opt 宣言指定子

7.1.5 型指定子 型指定子の構文規則は,次のとおりとする。
型指定子:
        単純型指定子
        クラス指定子
        列挙体指定子
        詳述型指定子
        cv 修飾子

7.1.5.2 単純型指定子 単純型指定子の構文規則は,次のとおりとする。
単純型指定子:
        ::opt 入れ子名前指定子opt 型名
        ::opt 入れ子名前指定子 template テンプレート識別子
        char
        wchar_t
        bool
        short
        int
        long
        signed
        unsigned
        float
        double
        void
型名:
        クラス名
        列挙体名
        型定義名

7.1.5.3 詳述型指定子
詳述型指定子:
        クラスキー ::opt 入れ子名前指定子opt 識別子
        クラスキー ::opt 入れ子名前指定子opt template opt テンプレート識別子
        enum ::opt 入れ子名前指定子opt 識別子
        typename ::opt 入れ子名前指定子 識別子
        typename ::opt 入れ子名前指定子 template opt テンプレート識別子

7.2 列挙体宣言 列挙体は,名前付き定数をもつ別個の型(3.9.1)とする。その名前は,その有効範囲内では《列挙体名》とする。
列挙体名:
        識別子
列挙体指定子:
        enum 識別子opt { 列挙子並びopt }
列挙子並び:
        列挙子定義
        列挙子並び , 列挙子定義
列挙子定義:
        列挙子
        列挙子 = 定数式
列挙子:
        識別子