名前空間の使い方

ついでに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";
}