厳密に型指定された列挙型

列挙は、整数定数を名前で定義する便利な方法です。これらの整数定数は列挙子と呼ばれます。残念ながら、従来の列挙型にはいくつかの欠点があります。

従来の C++ における列挙型の欠点

短いリマインダー。列挙型の 3 つの欠点

<オール>
  • 列挙子は暗黙的に int に変換されます。
  • エンクロージング スコープに列挙子を導入します。
  • 列挙型は指定できません。
  • まずポイント 3:列挙型は型が不明であるため、前方宣言できません。古典的な C++ の列挙子に対してのみ保証があります。型は整数で、列挙子を保持するのに十分な大きさでなければなりません。

    ポイント 1 とポイント 2 はさらに驚くべきことです。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // enumClassic.cpp
    
    #include <iostream>
    
    int main(){
     
     std::cout << std::endl;
     
     enum Colour{red= 0,green= 2,blue};
     
     std::cout << "red: " << red << std::endl;
     std::cout << "green: " << green << std::endl;
     std::cout << "blue: " << blue << std::endl;
     
     int red2= red;
     
     std::cout << "red2: " << red2 << std::endl;
     
     // int red= 5; ERROR
     
    }
    

    一方では、囲んでいるスコープで知られている赤、緑、青の列挙子があります。したがって、19 行目の変数 red の定義はできません。一方、赤は暗黙的に int に変換できます。

    enum{red, green, blue} のような列挙に名前を使用しない場合、列挙子は囲んでいるスコープに導入されます。

    しかし、その驚きは C++11 で終わります。

    厳密に型指定された列挙

    厳密に型指定された列挙は、より強力な規則に従う必要があります:

    <オール>
  • 列挙子は、列挙のスコープ内でのみアクセスできます。
  • 列挙子は暗黙的に int に変換されません。
  • 列挙子は外側のスコープにインポートされません。
  • 列挙子の型はデフォルトで int です。したがって、列挙を転送できます。
  • 従来の列挙と厳密に型指定された列挙の構文上の違いはごくわずかです。厳密に型指定された列挙は、キーワード class または struct を追加で取得します。

    列挙子を int として使用する場合は、static_cast で明示的に変換する必要があります。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // enumCast.cpp
    
    #include <iostream>
    
    enum OldEnum{
     one= 1,
     ten=10,
     hundred=100,
     thousand= 1000
    };
    
    enum struct NewEnum{
     one= 1,
     ten=10,
     hundred=100,
     thousand= 1000
    };
    
    int main(){
     
     std::cout << std::endl;
    
     std::cout << "C++11= " << 2*thousand + 0*hundred + 1*ten + 1*one << std::endl;
     std::cout << "C++11= " << 2*static_cast<int>(NewEnum::thousand) + 
     0*static_cast<int>(NewEnum::hundred) + 
     1*static_cast<int>(NewEnum::ten) + 
     1*static_cast<int>(NewEnum::one) << std::endl;
    
    }
    

    列挙子を計算または出力するには、それらを整数型に変換する必要があります。厳密に型指定された列挙の追加または出力が定義されています。

    この記事では、古典的な列挙型と厳密に型指定された列挙型についてよく話します。多くの場合、スコープ付きおよびスコープなしの列挙型と呼ばれます .

    型の明示的な指定

    C++11 の列挙型の 1 つの機能を無視しました。列挙子の型を明示的に指定できます。デフォルトでは int です。

    しかし、そうである必要はありません。 bool、char、short int、long int、long long int などの整数型を使用できます。詳細については、msdn.microsoft.com を参照してください。私の投稿 Check types how you can check at compile time if a type is integer を読むことができます。

    スコープ プロパティと列挙型の明示的な型指定を個別に使用できます。基本型に応じて、列挙型のサイズは異なります。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    // enumType.cpp
    
    #include <iostream>
    #include <climits>
    
    enum struct Colour0: bool{
     red, // 0
     blue // 1
    };
    
    enum Colour1{
     red= -5, 
     blue, // -4
     green // -3
    };
    
    enum struct Colour2: char{
     red= 100,
     blue, // 101
     green // 102
    };
    
    enum class Colour3: long long int{
     //red= std::numeric_limits<long long int>::min();
     red= LLONG_MIN,
     blue, // std::numeric_limits<long long int>::min() + 1
     green // std::numeric_limits<long long int>::min() + 2
    };
    
    int main(){
    
     std::cout << std::endl;
    
     std::cout << "sizeof(Colour0)= " << sizeof(Colour0) << std::endl;
     std::cout << "sizeof(Colour1)= " << sizeof(Colour1) << std::endl;
     std::cout << "sizeof(Colour2)= " << sizeof(Colour2) << std::endl;
     std::cout << "sizeof(Colour3)= " << sizeof(Colour3) << std::endl;
     
     std::cout << std::endl;
    
     std::cout << "Colour0::red: " << static_cast<bool>(Colour0::red) << std::endl;
     std::cout << "red: " << red << std::endl;
     std::cout << "Colour2::red: " << static_cast<char>(Colour2::red) << std::endl;
     std::cout << "Colour3::red: " << static_cast<long long int>(Colour3::red) << std::endl;
    
    }
    

    Microsoft Visual Studio 12.0 に含まれている C++ コンパイラ cl.exe は、コンパイル時に式 std::numeric_limits::min() (24 行目) を評価できません。 C++11 標準によると、std::numeric_limits::min() は定数式です。したがって、この式を使用して列挙子を初期化できます。 cl.exe に機能がないため、25 行目でマクロ LLONG_MIN を使用する必要があります。このマクロは、式 std::numeric_limits: と同じヘッダーで定義されています。

    最後に出力。

    次は?

    通常、組み込みの世界にはシステムのシステムがあります。別の言い方をすれば、多くの自律システムが相互に作用してシステム全体を構築しています。自律システムという用語をオブジェクトに置き換えると、私たちはオブジェクト指向プログラミングの領域にいます。私の見解では、オブジェクト指向の抽象化は、組み込みシステムをより深く理解するための大きな付加価値を持つ抽象化です。そのため、オブジェクト階層を管理できるようにする新しいキーワード override と final について、次の投稿で書きます。