English 中文(简体)
Enum scoping issues
原标题:

I try to keep things as local as possible, so I put enums at class scope, even if they are shared between two classes (I put it in the class that "goes better" with it.) This has worked out great, but I recently ran into an issue where a circular dependency will occur if I put the enum at class scope.

The enum is going to be a constructor argument for multiple classes, and the class it is in (and the class that makes the most sense for it to be in) includes those classes. Thus, it isn t possible to use the enum as a constructor argument for the classes included because it will result in a circular dependency.

Would it be better to just put this enum in its own header file, and if so, should I put all of the enums in the header file to be consistent? Are there any other solutions to this issue (that are logical)?

最佳回答

if the enum is used by multiple classes then i would say it does not really belong in the definition of a single class but in the namespace in which those classes reside.

that is unless the enumeration is being passed through one class to the constructor of another in which case it may make more sense to instantiate the enum dependant class seperately and pass it in as a parameter to the constructor of the containing class.

问题回答

Since C++11, you can use an enum class (or enum struct - the same thing, declared differently), where the enum values are scoped to the enum s name. For example, here is a valid C++11 declaration.

enum class token_type {
    open_paren,
    close_paren,
    identifier
};

To access the values of the enum, however, you must scope it correctly using the :: operator. Hence, this is a valid assignment in C++11:

token_type type = token_type::close_paren;

But this is not:

token_type type = close_paren;

This solves the naming conflict, and means you don t have to use container namespace or struct just to stop the scope of the values leaking to where they shouldn t. This means that the following enum can exist in the same scope as token_type:

enum class other_enum {
    block,
    thingy,
    identifier
};

Now the two values called identifier in the two different structs will not interfere.

I use a variant of what Michael and Roger do:

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

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

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

I find Color::Type to be prettier and more self-documenting than Color::Color or COLOR::Color. If you find Color::Type too verbose, you can use Color::T.

I don t prefix my enumerated values (i.e. COLOR_RED) because the namespace around the enum effectively becomes the prefix.

I ve stopped using the ALL_CAPS convention for my scoped constants because they clash with macros in C libraries (e.g. NULL). Macros aren t scoped in the namespaces they are defined in.

I often put my enums in a namespace to prevent the various enum values from cluttering up the global namespace. I think this is what you re trying to do by putting them in a class. But if they don t fit well in a class, a namespace works pretty much just as well for this purpose:

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


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

I have an editor snippet that builds the outline for a new enumeration given just it s name, including the

typedef enum FooSettings::FooSettings FooSettingsEnum;

line that creates a typedef so it s a tad more readable to declare variables with the enumeration s type.

I suspect that Stroustrup would have made enumeration value names scoped to the the enumeration if he had the opportunity, but C compatibility forced his hand (this is just speculation - maybe one day I ll look in D&E and see if he mentions anything).

I agree with Emile. Another option if you are using C++98 is to use struct instead of namespace, as follows

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

I prefer it since ideally I would use a namespace to represent a module that contains multiple classes, rather than just scoping an enum ...

You should place the enum outside of any class if it s shared, but you can still scope the enum. Place it in namespace so the enumerators don t "leak", cluttering your project s namespace:

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

You can try to forward declare the enum like this:

enum MyEnum;




相关问题
Finding the Highest Value in an Enumeration

I m writing a method which determines the highest value in a .NET enumeration so I can create a BitArray with one bit for each enum value: pressedKeys = new BitArray(highestValueInEnum<Keys>());...

Conversion of Enum to Enumerable

To convert Enum to Enumerable ,I use public enum Flags { Trivial=1, Minor, Major, Critical } IEnumerable<int> n = Enumerable.Range((int)Flags.Trivial, (...

Subclass check, is operator or enum check

A couple of friends was discussing the use of inheritance and how to check if a subclass is of a specific type and we decided to post it here on Stack. The debate was about if you should implement a ...

Enum scoping issues

I try to keep things as local as possible, so I put enums at class scope, even if they are shared between two classes (I put it in the class that "goes better" with it.) This has worked out great, but ...

How do I sort enum members alphabetically in Java?

I have an enum class like the following: public enum Letter { OMEGA_LETTER("Omega"), GAMMA_LETTER("Gamma"), BETA_LETTER("Beta"), ALPHA_LETTER("Alpha"), private final String ...

C++ enum value initialization

I have an enum declared in my code as: enum REMOTE_CONN { REMOTE_CONN_DEFAULT = 0, REMOTE_CONN_EX_MAN = 10000, REMOTE_CONN_SD_ANNOUNCE, REMOTE_CONN_SD_IO, REMOTE_CONN_AL, ...

WCF: Enforce equal DataContracts on both sides

I m wondering if it is possible to have WCF make sure that the DataContracts on both sides of a connection are exactly the same (and throw an exception when trying to connect if they are not). For ...

热门标签