Declaring an enum within a class

C++ClassEnumsNamespacesScope

C++ Problem Overview


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.)

C++ Solutions


Solution 1 - C++

  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 - C++

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 - C++

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 - C++

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 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbporterView Question on Stackoverflow
Solution 1 - C++Peter AlexanderView Answer on Stackoverflow
Solution 2 - C++Andreas FlorathView Answer on Stackoverflow
Solution 3 - C++Sergey TeplyakovView Answer on Stackoverflow
Solution 4 - C++Matthieu M.View Answer on Stackoverflow
Solution 5 - C++HarveyView Answer on Stackoverflow