namespaces for enum types - best practices

2019-01-12 17:08发布

Often, one needs several enumerated types together. Sometimes, one has a name clash. Two solutions to this come to mind: use a namespace, or use 'larger' enum element names. Still, the namespace solution has two possible implementations: a dummy class with nested enum, or a full blown namespace.

I'm looking for pros and cons of all three approaches.

Example:

// oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cColorBlue: //...
        //...
    }
 }


// (ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
 }


 // a real namespace?
 namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
 namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
 void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
  }

8条回答
唯我独甜
2楼-- · 2019-01-12 17:29

FYI In C++0x there is a new syntax for cases like what you mentioned (see C++0x wiki page)

enum class eColors { ... };
enum class eFeelings { ... };
查看更多
唯我独甜
3楼-- · 2019-01-12 17:33

I've hybridized the preceding answers to something like this: (EDIT: This is only useful for pre- C++11. If you are using C++11, use enum class)

I've got one big header file that contains all my project enums, because these enums are shared between worker classes and it doesn't make sense to put the enums in the worker classes themselves.

The struct avoids the public: syntactic sugar, and the typedef lets you actually declare variables of these enums within other worker classes.

I don't think using a namespace helps at all. Maybe this is because I'm a C# programmer, and there you have to use the enum type name when referring the values, so I'm used to it.

    struct KeySource {
        typedef enum { 
            None, 
            Efuse, 
            Bbram
        } Type;
    };

    struct Checksum {
        typedef enum {
            None =0,
            MD5 = 1,
            SHA1 = 2,
            SHA2 = 3
        } Type;
    };

    struct Encryption {
        typedef enum {
            Undetermined,
            None,
            AES
        } Type;
    };

    struct File {
        typedef enum {
            Unknown = 0,
            MCS,
            MEM,
            BIN,
            HEX
        } Type;
    };

...

class Worker {
    File::Type fileType;
    void DoIt() {
       switch(fileType) {
       case File::MCS: ... ;
       case File::MEM: ... ;
       case File::HEX: ... ;
    }
}
查看更多
Fickle 薄情
4楼-- · 2019-01-12 17:33

Since enums are scoped to their enclosing scope, it's probably best to wrap them in something to avoid polluting the global namespace and to help avoid name collisions. I prefer a namespace to class simply because namespace feels like a bag of holding, whereas class feels like a robust object (cf. the struct vs. class debate). A possible benefit to a namespace is that it can be extended later - useful if you're dealing with third-party code that you cannot modify.

This is all moot of course when we get enum classes with C++0x.

查看更多
狗以群分
5楼-- · 2019-01-12 17:34

I would definitely avoid using a class for this; use a namespace instead. The question boils down to whether to use a namespace or to use unique ids for the enum values. Personally, I'd use a namespace so that my ids could be shorter and hopefully more self-explanatory. Then application code could use a 'using namespace' directive and make everything more readable.

From your example above:

using namespace Colors;

void setPenColor( const e c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cBlue: //...
        //...
    }
}
查看更多
倾城 Initia
6楼-- · 2019-01-12 17:39

Advantage of using a class is that you can build a full-fledged class on top of it.

#include <cassert>

class Color
{
public:
    typedef enum
    {
        Red,
        Blue,
        Green,
        Yellow
    } enum_type;

private:
    enum_type _val;

public:
    Color(enum_type val = Blue)
        : _val(val)
    {
        assert(val <= Yellow);
    }

    operator enum_type() const
    {
        return _val;
    }
};

void SetPenColor(const Color c)
{
    switch (c)
    {
        case Color::Red:
            // ...
            break;
    }
}

As the above example shows, by using a class you can:

  1. prohibit (sadly, not compile-time) C++ from allowing a cast from invalid value,
  2. set a (non-zero) default for newly-created enums,
  3. add further methods, like for returning a string representation of a choice.

Just note that you need to declare operator enum_type() so that C++ would know how to convert your class into underlying enum. Otherwise, you won't be able to pass the type to a switch statement.

查看更多
【Aperson】
7楼-- · 2019-01-12 17:44

An difference between using a class or a namespace is that the class cannot be reopened like a namespace can. This avoids the possibility that the namespace might be abused in the future, but there is also the problem that you cannot add to the set of enumerations either.

A possible benefit for using a class, is that they can be used as template type arguments, which is not the case for namespaces:

class Colors {
public:
  enum TYPE {
    Red,
    Green,
    Blue
  };
};

template <typename T> void foo (T t) {
  typedef typename T::TYPE EnumType;
  // ...
}

Personally, I'm not a fan of using, and I prefer the fully qualified names, so I don't really see that as a plus for namespaces. However, this is probably not the most important decision that you'll make in your project!

查看更多
登录 后发表回答