Declaring an enum within a class

288,628

Solution 1

  1. If Color is something that is specific to just Cars then that is the way you would limit its scope. If you are going to have another Color enum that other classes use then you might as well make it global (or at least outside Car).

  2. It makes no difference. If there is a global one then the local one is still used anyway as it is closer to the current scope. Note that if you define those function outside of the class definition then you'll need to explicitly specify Car::Color in the function's interface.

Solution 2

Nowadays - using C++11 - you can use enum class for this:

enum class Color { RED, BLUE, WHITE };

AFAII this does exactly what you want.

Solution 3

I prefer following approach (code below). It solves the "namespace pollution" problem, but also it is much more typesafe (you can't assign and even compare two different enumerations, or your enumeration with any other built-in types etc).

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;
};

Usage:

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

I create macro to facilitate usage:

#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),

Usage:

DEFINE_SIMPLE_ENUM(Color,
             ((Red, 1))
             ((Green, 3))
             )

Some references:

  1. Herb Sutter, Jum Hyslop, C/C++ Users Journal, 22(5), May 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup Strongly Typed Enums (revision 3), July 2007

Solution 4

In general, I always put my enums in a struct. I have seen several guidelines including "prefixing".

enum Color
{
  Clr_Red,
  Clr_Yellow,
  Clr_Blue,
};

Always thought this looked more like C guidelines than C++ ones (for one because of the abbreviation and also because of the namespaces in C++).

So to limit the scope we now have two alternatives:

  • namespaces
  • structs/classes

I personally tend to use a struct because it can be used as parameters for template programming while a namespace cannot be manipulated.

Examples of manipulation include:

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

which returns the number of elements of enum inside the struct T :)

Solution 5

If you are creating a code library, then I would use namespace. However, you can still only have one Color enum inside that namespace. If you need an enum that might use a common name, but might have different constants for different classes, use your approach.

Share:
288,628

Related videos on Youtube

bporter
Author by

bporter

Updated on November 02, 2020

Comments

  • bporter
    bporter over 3 years

    In the following code snippet, the Color enum is declared within the Car class in order to limit the scope of the enum and to try not to "pollute" the global namespace.

    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) Is this a good way to limit the scope of the Color enum? Or, should I declare it outside of the Car class, but possibly within its own namespace or struct? I just came across this article today, which advocates the latter and discusses some nice points about enums: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums.

    (2) In this example, when working within the class, is it best to code the enum as Car::Color, or would just Color suffice? (I assume the former is better, just in case there is another Color enum declared in the global namespace. That way, at least, we are explicit about the enum to we are referring.)

  • Matthieu M.
    Matthieu M. about 14 years
    2. Yes and no. Car::Color getColor() but void Car::setColor(Color c) because in setColor we already have the specifier.
  • jmucchiello
    jmucchiello about 14 years
    I like this. It also forces the enum to be instantiated with a valid value. I do think an assignment operator and copy constructor would be useful. Also t_ should be private. The macros I can do without.
  • anio
    anio over 13 years
    I too like this. Thanks for the references.
  • Nawaz
    Nawaz about 11 years
    You said : "also it is much more typesafe (you can't assign and even compare two different enumerations ...". Why do you think it is a good feature? I think if(c2 == Color::Red ) is reasonable and must compile, but in your example it doesn't. Same argument for assignment also!
  • Victor K
    Victor K almost 11 years
    @Nawaz c2 is of another type (Color2), so why do you think c2 == Color::Red and assignments should compile? What if Color::Red is 1, and Color2::Red is 2? Should Color::Red == Color2::Red evaluate to true or false? If you mix non-typesafe enumerators, you're gonna have a bad time.
  • Nawaz
    Nawaz almost 11 years
    @VictorK: Ohh. I didn't notice that c2 is of different type! Now this post makes sense to me. Thanks. (+1)
  • Zingam
    Zingam over 10 years
    Why isnt Type t_; private?
  • Andreas detests censorship
    Andreas detests censorship about 5 years
    Sadly, it doesn't allow member functions: stackoverflow.com/a/53284026/7395227