名前空間の使い方
ついでにenumの話
通常のenumの使い方(Cのenum)
- "enumの使い方"
#include <iostream> //画像ファイルの色を表したいenum enum Colors { RED = 0, GREEN, BLUE, ALPHA, }; //enum Renger //{ // RED, BULE, PINK, GREEN, YELLOW, //}; const int ImageWidth = 600; const int ImageHeight = 400; //画像のピクセルを表す配列(3次元怖い) unsigned char ColorImage[ImageWidth][ImageHeight][4]; int main() { //画像の色を黒で初期化 for(auto j=0;j<ImageHeight;j++){ for(auto i=0;i<ImageWidth;i++){ ColorImage[i][j][RED] = 0; ColorImage[i][j][GREEN] = 0; ColorImage[i][j][BLUE] = 0; ColorImage[i][j][ALPHA] = 255; } } }
こんな感じで、整数値として使えます。
これはもはや、これとほとんど同じです。
#define RED 0 #define GREEN 1 #define BLUE 2 #define ALPHA 3
これを、勝手にリストを作ると、初期値から1ずつ値を増やしてくれる便利な整数の定数が作れます。
が通常のenumになります。
初期値をずらすこともできます。
for文で使うこともできるし、switch-case文で使うこともできます。便利!
けど、こんなことが起こります。
球にプログラムに、戦隊ものの要素を加えようと思い、こんなenumを追加します。
- "戦隊もの作るぞ"
enum Renger { RED, BULE, PINK, GREEN, YELLOW, };
これで、画像の色の他に、戦隊ものヒーローの色を扱うenumが。。。できない。
何かわかんないけど、C++の始祖であるC言語の時代からあるenumの仕組みではなんとenumの種類が違っても同じ名前のenumのメンバは作れないようです(´;ω;`)
C++の新しいenum
C++は、アクセスやスコープを制限して、安全性を高める言語でしたね!
そんなC++に2011年のバージョンアップの時に(C++11)新しい仲間が増えました。
(僕が1993年にC++を習った時にはテンプレートもなかったんだぞ)
それが、```enum struct```(```enum class```)です。
これを使うと、さっきの問題が。。。
- "スコープ付きenum"
enum struct Colors { RED = 0, GREEN, BLUE, ALPHA, }; enum struct Renger { RED, BULE, PINK, GREEN, YELLOW, };
これで、enumにスコープを付けることができて、Colors::REDと、Renger::REDは全く別のスコープに存在するので区別されるようになります。
解決!。。。って思うじゃん。
配列の要素指定が整数ではありません。って言われてしまいました。
これは困った。
実は、スコープが付いたのはいいけれど、```enum class```や```enum struct```は整数の値を持った、列挙型と言う型ですが、整数型自体とは異なる型として扱われます。
Cのenumはただの整数だったので楽だったね。。。
整数として使いたいときは(多分その使い方がすでに間違ってんだろね。。。)型変換を行います。
- "enum classのメンバの型変換"
ColorImage[i][j][static_cast<int>(Colors::RED)] = 0; ColorImage[i][j][static_cast<int>(Colors::GREEN)] = 0; ColorImage[i][j][static_cast<int>(Colors::BLUE)] = 0; ColorImage[i][j][static_cast<int>(Colors::ALPHA)] = 255;
ちなみに
本来は、整数値として使うのではなく、もう、この```enum class```しか受け取らないよ。と言う形での使い方が正しいです。
上の、整数値のやつはスコープとしては、
const int RED = 0; const int GREEN = 1; const int BLUE = 2; const int ALPHA = 3;
と一緒で、列挙したときに自動で値を1個ずつ増やしてくれるのが便利、なだけの使い方をしているってことになります。
本来は、以下の様に、enum classを使うことによって、それ以外の型は受け付けないので間違いを防ぐ、という使い方の方が正しいです。
- "正しいenum classの使い方"
#include <iostream> #include <string> enum class CardMark { spade, club, diamond, heart, }; std::string get_mark_string(CardMark card_mark) { // switch文の caseラベルに使える switch (card_mark) { case CardMark::spade: return "spade"; case CardMark::club: return "club"; case CardMark::diamond: return "diamond"; case CardMark::heart: return "heart"; default: return ""; } } int main() { CardMark mark {CardMark::spade}; // 変数の宣言と初期化 mark = CardMark::diamond; // 代入 std::cout << std::boolalpha << (mark == CardMark::diamond) << "\n"; // 比較 std::cout << get_mark_string(mark) << "\n"; }
