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


150

次のコードスニペットでは、Color列挙型Carのスコープを制限し、グローバル名前空間を「汚染」しないようにするために、列挙型がクラス内で宣言されています。

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列挙型の範囲を制限する良い方法ですか?または、Carクラス外で宣言する必要がありますが、独自の名前空間または構造内で宣言する必要がありますか?私は本日この記事に出くわしました。後者は、後者を支持し、列挙に関するいくつかの良い点を議論していますhttp : //gamesfromwithin.com/stupid-c-tr​​icks-2-better-enums

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

回答:


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

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


12
2.はい、いいえ。Car::Color getColor()しかし、void Car::setColor(Color c)中にいるのでsetColor、私たちは、すでに指定子を持っています。
Matthieu M.10年


66

私は次のアプローチを好む(以下のコード)。「名前空間の汚染」の問題を解決しますが、さらにタイプセーフです(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. ハーブサッター、デビッドE.ミラー、ビャルネストロストラップ強く型付けされた列挙型(リビジョン3)、2007年7月

私はこれが好き。また、列挙型を有効な値でインスタンス化するように強制します。代入演算子とコピーコンストラクターが役立つと思います。また、t_はプライベートである必要があります。なしでできるマクロ。
jmucchiello 2010年

私もこれが好きです。参照をありがとう。
anio

1
あなたは言った:「また、それははるかにタイプセーフです(2つの異なる列挙を割り当て、比較することさえできません...」。なぜそれは良い機能だと思いますか?if(c2 == Color::Red )合理的でコンパイルする必要があると思いますが、あなたの例ではそれ割り当てについても同じ議論です!
Nawaz

3
@Nawaz c2は別のタイプ(Color2)ですが、なぜc2 == Color::Red割り当てをコンパイルする必要があると思いますか?Color::Red1でColor2::Red2の場合はどうなりますか?すべきであるColor::Red == Color2::Redと評価さtruefalse?タイプセーフでない列挙子を混在させると、悪い時間になります。
ビクターK

2
なぜタイプt_ではないのですか?民間?
Zingam 2013

7

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

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

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

したがって、範囲を制限するために、2つの選択肢があります。

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

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

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

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

構造体内の列挙型の要素の数を返しますT:)


3

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.