次のコードスニペットでは、Color
enumをCar
クラス内で宣言して、enumのスコープを制限し、グローバルネームスペースを「汚染」しないようにしています。
class Car
{
public:
enum Color
{
RED,
BLUE,
WHITE
};
void SetColor( Car::Color color )
{
_color = color;
}
Car::Color GetColor() const
{
return _color;
}
private:
Car::Color _color;
};
(1)これはColor
enumのスコープを制限する良い方法ですか?または、Car
クラスの外で宣言する必要がありますが、おそらく独自の名前空間または構造体内で宣言する必要がありますか?私は今日この記事に出くわしました。後者を支持し、列挙型に関するいくつかの素晴らしい点について議論します: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums 。
(2)この例では、クラス内でを使用する場合、enumをCar::Color
としてコーディングするのが最善ですか、それともColor
で十分ですか? (グローバル名前空間で宣言された別のColor
enumがある場合に備えて、前者の方が優れていると思います。そのように、少なくとも、参照しているenumについては明示的です。)
Color
がCar
sだけに固有のものである場合、それがスコープを制限する方法です。他のクラスが使用する別のColor
列挙型を使用する場合は、グローバル(または少なくともCar
の外側)にすることもできます。
違いはありません。グローバルなものがある場合、現在のスコープに近いため、ローカルなものが使用されます。これらの関数をクラス定義の外部で定義する場合、関数のインターフェースでCar::Color
を明示的に指定する必要があることに注意してください。
私は次のアプローチを好む(以下のコード)。 「名前空間の汚染」問題を解決しますが、さらにタイプセーフです(2つの異なる列挙型、または他の組み込み型などと列挙型を割り当てたり、比較することもできません)。
struct Color
{
enum Type
{
Red, Green, Black
};
Type t_;
Color(Type t) : t_(t) {}
operator Type () const {return t_;}
private:
//prevent automatic conversion for any other built-in types such as bool, int, etc
template<typename T>
operator T () const;
};
使用法:
Color c = Color::Red;
switch(c)
{
case Color::Red:
//некоторый код
break;
}
Color2 c2 = Color2::Green;
c2 = c; //error
c2 = 3; //error
if (c2 == Color::Red ) {} //error
If (c2) {} error
使用を容易にするマクロを作成します。
#define DEFINE_SIMPLE_ENUM(EnumName, seq) \
struct EnumName {\
enum type \
{ \
BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\
}; \
type v; \
EnumName(type v) : v(v) {} \
operator type() const {return v;} \
private: \
template<typename T> \
operator T () const;};\
#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \
BOOST_PP_Tuple_ELEM(2, 0, record) = BOOST_PP_Tuple_ELEM(2, 1, record),
使用法:
DEFINE_SIMPLE_ENUM(Color,
((Red, 1))
((Green, 3))
)
いくつかの参照:
一般的に、列挙型は常にstruct
に入れます。 「プレフィックス」を含むいくつかのガイドラインを見てきました。
enum Color
{
Clr_Red,
Clr_Yellow,
Clr_Blue,
};
これは、C++
のガイドラインよりもC
のガイドラインのように見えると常に考えていました(1つは、略語とC++
の名前空間のためです)。
したがって、スコープを制限するために、2つの選択肢があります。
個人的にはstruct
を使用する傾向があります。これは、名前空間を操作できないときにテンプレートプログラミングのパラメーターとして使用できるためです。
操作の例は次のとおりです。
template <class T>
size_t number() { /**/ }
struct T
内のenumの要素数を返します:)
コードライブラリを作成する場合は、名前空間を使用します。ただし、その名前空間内には1つのColor列挙しか保持できません。共通名を使用しても、クラスごとに異なる定数を持つ列挙型が必要な場合は、アプローチを使用してください。