Enum范围问题

时间:2009-11-15 17:56:18

标签: c++ scope enums

我尝试尽可能保持本地的内容,所以我把枚举放在类范围内,即使它们在两个类之间共享(我把它放在“更好”的类中。)这样做很棒但是我最近遇到了一个问题,如果我将枚举放在类范围内,就会出现循环依赖。

枚举将成为多个类的构造函数参数,它所在的类(以及最适合它的类)包括这些类。因此,不可能将枚举用作包含的类的构造函数参数,因为它将导致循环依赖。

将此枚举放在自己的头文件中会不会更好,如果是这样,我应该将头文件中的所有枚举保持一致吗?这个问题还有其他解决办法吗(这是合乎逻辑的)?

7 个答案:

答案 0 :(得分:13)

从C ++ 11开始,你可以使用enum class(或enum struct - 相同的东西,声明不同),其中枚举值的范围限定为枚举的名称。例如,这是一个有效的C ++ 11声明。

enum class token_type {
    open_paren,
    close_paren,
    identifier
};

要访问枚举的值,您必须使用::运算符正确地对其进行范围调整。因此,这是C ++ 11中的有效赋值:

token_type type = token_type::close_paren;

但这不是:

token_type type = close_paren;

这解决了命名冲突,这意味着您不必使用容器命名空间或结构只是为了阻止值泄漏到不应该的位置。这意味着以下枚举可以与token_type

在同一范围内
enum class other_enum {
    block,
    thingy,
    identifier
};

现在两个不同结构中名为identifier的两个值不会干扰。

答案 1 :(得分:8)

我使用Michael和Roger所做的变体:

namespace Color
{
   enum Type
   {
      red,
      green,
      blue
   };
};

void paintHouse(Color::Type color) {...}

main()
{
   paintHouse(Color::red);
}

我发现Color::TypeColor::ColorCOLOR::Color更漂亮,更自我记录。如果您发现Color::Type过于冗长,可以使用Color::T

我没有为枚举值添加前缀(即COLOR_RED),因为枚举周围的命名空间实际上成为前缀。

我已经停止对我的作用域常量使用ALL_CAPS约定,因为它们与C库中的宏冲突(例如NULL)。宏未定义在它们定义的名称空间中。

答案 2 :(得分:4)

如果enum被多个类使用,那么我会说它并不真正属于单个类的定义,而是属于这些类所在的命名空间。

除非枚举通过一个类传递给另一个类的构造函数,否则在单独实例化枚举依赖类并将其作为参数传递给包含类的构造函数可能更有意义。 / p>

答案 3 :(得分:3)

我经常将我的枚举放在命名空间中,以防止各种枚举值混乱全局命名空间。我认为这就是你把它们放在课堂上所要做的。但是如果它们在一个类中“不适合”,那么命名空间就可以用于此目的:

namespace FooSettings
{
    enum FooSettings
    {
        foo,
        bar
    };
}
typedef enum FooSettings::FooSettings FooSettingsEnum;


int main()
{
    FooSettingsEnum x = FooSettings::foo;
};

我有一个编辑器代码段,根据它的名称构建新枚举的大纲,包括

typedef enum FooSettings::FooSettings FooSettingsEnum;

创建一个typedef的行,因此使用枚举类型声明变量更具可读性。

我怀疑如果有机会,Stroustrup会将枚举值名称作为枚举范围,但C兼容性强迫他的手(这只是推测 - 也许有一天我会看D& E看看是否他提到了什么。)

答案 4 :(得分:2)

如果共享的话,你应该将枚举放在任何类之外,但你仍然可以使用枚举范围。将它放在命名空间中,这样枚举器就不会“泄漏”,使项目的命名空间变得混乱:

namespace Project { // you already have this, right? :)
  namespace COLOR { // naming styles differ, use what you like
    enum Color {
      red,
      green,
      blue
    };
  }
  using COLOR::Color; // now you can use the type 'normally'

  // examples:
  struct A {
    Color c;
    A() : c(COLOR::red) {}
  };
  void f(Color c) {
    using namespace COLOR;
    // inside this function, we no longer have to prefix COLOR::
    if (c == green) {
      go();
    }
    else if (c == red) {
      stop();
    }
  }
}

答案 5 :(得分:2)

我同意埃米尔的观点。如果使用C ++ 98,另一个选择是使用struct而不是namespace,如下所示

struct Color
{
   enum Type
   {
    red,
    green,
    blue
   };
};

我更喜欢它,因为理想情况下我会使用命名空间来表示包含多个类的模块,而不仅仅是确定枚举范围...

答案 6 :(得分:-2)

你可以试着像这样向前声明枚举:

enum MyEnum;