views:

124

answers:

3

I am maintaining a large code base and am using a combination of forward declarations and the pImpl idiom to keep compile times down and reduce dependencies (and it works really well,)

The problem I have is with classes that contain public enumerations. These enumerations cannot be forward declared so I am left with no option but to include the class header. For example:

// Foo.h

class Foo
{
public:
  enum Type
  {
    TYPE_A,
    TYPE_B,
  };
  ...
};

// Bar.h

#include "Foo.h" // For Foo::Type

class Bar
{
public:
  void someFunction(Foo::Type type);
  ...
};

So, I'm looking for ways to avoid this and can only think of the following:

Move the class enumerations to a separate 'types' namespace

// FooTypes.h

namespace FooTypes
{
  enum Type
  {
    TYPE_A,
    TYPE_B,
  };
}

// Bar.h

#include "FooTypes.h"

class Bar
{
public:
  void someFunction(FooTypes::Type type);
  ...
};

Use int instead of the enumeration

// Bar.h

class Bar
{
public:
  void someFunction(int type);
  ...
};

What have I missed? How do other people get around this limitation (not being able to forward declare enumerations.)

+3  A: 

Put the enumeration in the class containing the PIMPL.

anon
But Foo::Type needs to be used by lots of other classes, not just Bar. I should of made this clear.
Rob
A PIMPL points to the implementation of a specific class. If the implememntation is used in more than one class, then I think you have a design issue.
anon
Confused. I have a class, Foo, containing a public enum. I want to know ways to forward declare this enum so I don't need to #include Foo.h when another class needs to use the enum as a method argument. We seem to be at cross-purposes here - I obviously didn't phrase my question very well! :)
Rob
Sorry, I thought you were asking about using enums in concert with pimpls.
anon
+2  A: 

Put the enumeration into its own type:

struct FooEnum
{
  enum Type
  {
    TYPE_A,
    TYPE_B,
  };
};

Then Foo and Bar can both access FooEnum::Type and Bar.h doesn't need to include Foo.h.

jon hanson
This is similar to my 'put the enumeration in a namespace' idea. Does adding it to a struct give me any other benefits?
Rob
Agreed. Not many benefits other than i guess you have the option of Foo and Bar inheriting from FooEnum to directly acquire the enum type. Not sure i'd recommend that though.
jon hanson
The real benefit is to manipulate it trough templates, namespaces cannot be used as template arguments. For example, most of our enums have to 'fixed' values: Invalid (0) is the minimum and NumberOfElements the maximum (works if contiguous), so we can use templates to check the value is in range etc...
Matthieu M.
Thanks Matthieu - i think that was what i had in mind originally but forgot after posting...
jon hanson
A: 

I'd argue that enums are a bad idea to start with, but in general for constants/the many things like constants in C++ none of which are quite constants and all of which have issues. I like to put it into a struct then have the classes using it inherit from the struct.

I'd also argue that the pimpl idiom is bad. Actually I am sure it's a poor way to do things. It's something that works but is awkward and a bit silly. It's also easy to avoid, and the only reason it comes about is due to people using yet other bad design choices.

Usually someone just tacks on OOP stuff to a class they designed to be concrete. Then you get the mixed inheritance case and the plethora of issues it causes such as super slow compile time. Instead, consider pure virtual base classes, then writing your libs to that to avoid templates and avoid the forward declaration problem. Not for everything, but definitely for the cases where you are generating code for lots of classes.

Charles Eli Cheese