web-dev-qa-db-ja.com

クラス内で列挙型を宣言する

次のコードスニペットでは、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-tr​​icks-2-better-enums

(2)この例では、クラス内でを使用する場合、enumをCar::Colorとしてコーディングするのが最善ですか、それともColorで十分ですか? (グローバル名前空間で宣言された別のColor enumがある場合に備えて、前者の方が優れていると思います。そのように、少なくとも、参照しているenumについては明示的です。)

136
bporter
  1. ColorCarsだけに固有のものである場合、それがスコープを制限する方法です。他のクラスが使用する別のColor列挙型を使用する場合は、グローバル(または少なくともCarの外側)にすることもできます。

  2. 違いはありません。グローバルなものがある場合、現在のスコープに近いため、ローカルなものが使用されます。これらの関数をクラス定義の外部で定義する場合、関数のインターフェースでCar::Colorを明示的に指定する必要があることに注意してください。

78
Peter Alexander

最近では、C++ 11を使用して、enum classを使用できます:

enum class Color { RED, BLUE, WHITE };

AFAIIこれはまさにあなたが望むことをします。

78
Andreas Florath

私は次のアプローチを好む(以下のコード)。 「名前空間の汚染」問題を解決しますが、さらにタイプセーフです(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))
             )

いくつかの参照:

  1. Herb Sutter、Jum Hyslop、C/C++ Users Journal、22(5)、2004年5月
  2. Herb Sutter、David E. Miller、Bjarne Stroustrup厳密に型指定された列挙(改訂3)、2007年7月
62

一般的に、列挙型は常にstructに入れます。 「プレフィックス」を含むいくつかのガイドラインを見てきました。

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

これは、C++のガイドラインよりもCのガイドラインのように見えると常に考えていました(1つは、略語とC++の名前空間のためです)。

したがって、スコープを制限するために、2つの選択肢があります。

  • 名前空間
  • 構造体/クラス

個人的にはstructを使用する傾向があります。これは、名前空間を操作できないときにテンプレートプログラミングのパラメーターとして使用できるためです。

操作の例は次のとおりです。

template <class T>
size_t number() { /**/ }

struct T内のenumの要素数を返します:)

7
Matthieu M.

コードライブラリを作成する場合は、名前空間を使用します。ただし、その名前空間内には1つのColor列挙しか保持できません。共通名を使用しても、クラスごとに異なる定数を持つ列挙型が必要な場合は、アプローチを使用してください。

3
Harvey