tags:

views:

266

answers:

5

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

A: 

You can try to forward declare the enum like this:

enum MyEnum;
gatorfax
Enums can't be forward declared.
Anonymous
And even if you could, you can't forward declare nested types. Or rather, you can't forward declare a nested type without having the definition of the nesting type.
Logan Capaldo
A: 

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.

dice
The second thing you described is the case, but the method you described won't work. I've decided to just make the the enums available in a utility header that has commonly used methods, etc.
Anonymous
+1  A: 

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();
    }
  }
}
Roger Pate
I'll have to try using the `using` s=declaration like you do to see if I like it better than the `typedef` mess that I've been using. I think I'll like it (but may use a different naming convention than all caps for the enum type). Thanks!
Michael Burr
I used CAPS because it seemed Color would be used more than COLOR::red, or you'd use the latter often and can use a using-directive at function scope. `typedef COLOR::Color Color;` is equivalent to `using COLOR::Color;` here.
Roger Pate
+1  A: 

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

Michael Burr
I personally prefer a struct than a namespace because a struct is then manipulable from templates.
Matthieu M.
@Matthieu - Using a struct simply never came to mind. I can't say I've missed not being able to manipulate the enums with templates, but I certainly see no downside to using a struct to wrap the enum scope either. Yet another good idea for me to use. Thanks.
Michael Burr
I tried encapsulating enums in a namespace and also in a struct, and some things work better with a struct. So I often do the following: struct MyEnum { enum Values{a, b}; }; typedef MyEnum::Values MyEnum_t; Now I can use `MyEnum_t` to refer to the enum as a type, and `MyEnum::a`, `MyEnum::b` to refer to its members as if the enum were an aggregate type. I experimented a while before choosing the particular naming conventions here and I have over time found the above to be as good as I can do.
Permaquid
+1  A: 

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.

Emile Cormier
I'm now considering adopting Matthieu M's suggestion of using struct instead of namespace to be able to pass it as a template parameter. However, I can't think of a reason why I'd pass Color instead of Color::Type as a template parameter.
Emile Cormier