Suppose I have
enum class Colour
{
red,
blue,
orange
};
class PencilBase
{
public:
virtual void paint() = 0;
};
template <Colour c>
class Pencil : public PencilBase
{
void paint() override
{
// use c
}
};
Now I want to have some factory function to create painters
PencilBase* createColourPencil(Colour c);
What will be the most elegant way to implement this function?
I want to avoid making changes in this function (or its helpers) when I decide to introduce a new colour.
I feel like we have all the information at compile time to achieve this, however I am having trouble to find a solution.
Firstly, you need to know how many colors are there:
enum class Colour
{
red,
blue,
orange,
_count, // <--
};
After you know the number, you can create an array of function pointers of this size, each function creating the respective class. Then you use the enum as an index into the array, and call the function.
std::unique_ptr<PencilBase> createColourPencil(Colour c)
{
if (c < Colour{} || c >= Colour::_count)
throw std::runtime_error("Invalid color enum.");
static constexpr auto funcs = []<std::size_t ...I>(std::index_sequence<I...>)
{
return std::array{+[]() -> std::unique_ptr<PencilBase>
{
return std::make_unique<Pencil<Colour(I)>>();
}...};
}(std::make_index_sequence<std::size_t(Colour::_count)>{});
return funcs[std::size_t(c)]();
}
Template lambas require C++20. If you replace the outer lambda with a function, it should work in C++17 as well.
MSVC doesn't like the inner lambda, so if you're using it, you might need to convert it to a function too. (GCC and Clang have no problem with it.)
I've used unique_ptr here, but nothing stops you from using the raw pointers.
gcc 7.3.1 is not able to handle this code
Here it is, ported to GCC 7.3:
template <Colour I>
std::unique_ptr<PencilBase> pencilFactoryFunc()
{
return std::make_unique<Pencil<I>>();
}
template <std::size_t ...I>
constexpr auto makePencilFactoryFuncs(std::index_sequence<I...>)
{
return std::array{pencilFactoryFunc<Colour(I)>...};
}
std::unique_ptr<PencilBase> createColourPencil(Colour c)
{
if (c < Colour{} || c >= Colour::_count)
throw std::runtime_error("Invalid color enum.");
static constexpr auto funcs = makePencilFactoryFuncs(std::make_index_sequence<std::size_t(Colour::_count)>{});
return funcs[std::size_t(c)]();
}
I don't think there are millions of solutions no ?
PencilBase* createColourPencil(Colour c)
{
switch (c)
{
case Colour::red:
return new Pencil<Colour::red> ();
break;
...
default:
break;
}
}
You have several good possibilities:
PencilBase* createPencil (Colour colour) {
switch (colour) {
case RED:
return new Pencil<RED>();
case BLUE:
return new Pencil<BLUE>();
...
default:
throw std::invalid_argument("Unsupported colour");
}
}
or why not a more modern construct like this one, which has the advantage to be potentially updated at runtime:
std::unordered_map<Colour, std::function<PencilBase*()>> FACTORIES = {
{ RED, [](){ new Pencil<RED>(); } },
{ BLUE, [](){ new Pencil<BLUE>(); } },
...
};
PencilBase* createPencil (Colour colour) {
return FACTORIES[colour]();
}
However, none can completely fullfill what you ask:
I want to avoid making changes in this function (or its helpers) when I decide to introduce a new colour. I feel like we have all the information at compile time to achieve this
There are at least two reasons for this:
Your colour parameter given to your factory is known at runtime, while your template parameter must be known at compile time.
There is no built-in solution to enumerate or go through all enum values
There isn't many solutions to go against the first point, except avoiding templates if you can.
In your case, is there a good reason to use templates ? Do you really need to use a completely different class ? Can't you change your template into a normal parameter passed in the constructor or as a class member ?
If you have no choice to use templates, there exist a way to avoid repeating yourself. You may use good old macros and in a kind of special way commonly called X-macro. Quick example:
colours.hpp:
COLOUR(RED)
COLOUR(BLUE)
COLOUR(ORANGE)
Colour.hpp:
enum Colour {
#define COLOUR(C) C,
#include "colours.hpp"
#undef COLOUR
INVALID_COLOUR
};
Factory function:
PencilBase* createPencil (Colour colour) {
switch(colour) {
#define COLOUR(C) case C: return new Pencil<C>();
#include "colours.hpp"
#undef COLOUR
default:
throw new std::invalid_argument("Invalid colour");
}
}
This will basicly rewrite the switch given as first example. You may as well change the macro to rewrite the mapping. However, as you can see, it may not be more readable or maintainable than to be explicit.
Related
I am writing a function that takes the enum MyEnum as input. Depending on the value of MyEnum, I initialize an object and process it. I cannot change the class hierarchy of those objects (their classes), since they are from an external dependency. Processing the newly created object is always the same.
Question:
How can I write this "elegantly". I do not want to write a long if, else if, else block that repeats itself over and over, which is what I currently do. What I would like to have is some magic function that tells me the type to use at runtime. Afaik this does not exist.
What I would like to have:
magic_function(enum_known_at_runtime) my_object;
What I would use if I knew the value at compile time: play with code
enum class MyEnum { A, B , /* many more values */ };
template <MyEnum>
struct get_type;
template <>
struct get_type<MyEnum::A> {
using Type = unsigned int; // some type
};
...
int main() {
get_type<enum_known_at_compiletime>::Type i;
// do stuff with i
}
What I currently do:
if (enum_known_at_runtime == MyEnum::A) {
// init an object of some type and do stuff with it
} else if (enum_known_at_runtime == MyEnum::A) {
// init an object of other type and do same stuff with it
} ...
Let us assume you capture the repeated code in a templated function and define corresponding instantiations for get_type:
template <MyEnum E>
struct get_type;
template <MyEnum E>
void init_object_do_stuff() {
using T = get_type<E>::type;
T client;
client.do_stuff();
}
You can now write your repeated code as follows:
switch (enum_known_at_runtime) {
case MyEnum::A: init_object_do_stuff<MyEnum::A>(); break;
case MyEnum::B: init_object_do_stuff<MyEnum::B>(); break;
}
Now the work for new enums is adding a single line and an extra case for get_type, which you can further shrink using a macro. As a bonus, the compiler will yell at you if your switch does not cover all cases.
I'm currently working on an image processing application, mainly based on C++ and ITK.
1. The Situation
I have node classes (e.g. FlipFilter) derived from the same base class. A node gets a struct with an image_ptr and all of the meta-information (dimension of the Image, PixelType (e.g. RGB, RGBA, scalar) and ComponentType (e.g. Float, int). The node has to instantiate an ITK-Filter, based on these Meta-Informations, which can change on every input-image.
2. The Problem
These ITK-Filters need the ImageType (e.g. RGB with ComponentType UCHAR) as a template argument. A template class has to be instantiated at compile-time. My node is getting the image with its type at runtime. So I somehow have to create all permutations of the filter for each node and then use the appropriate instantiation.
3. My current Solution
This struct contains all the meta-information + a smart-pointer pointing towards the actual image.
I'm using a base pointer of the image because the image itself is also a template (later I'm downcasting).
struct ImageData
{
short NumberOfDimensions;
itk::ImageIOBase::IOComponentType ComponentType;
itk::ImageIOBase::IOPixelType PixelType;
itk::DataObject::Pointer Image;
ImageData() {}
~ImageData() {}
};
This is the update function of my node. It is supposed to create the filter an execute it on an image.
void LitkFlipImageFilter::update()
{
if (Input1 == nullptr)
throw(std::runtime_error("Input1 not set"));
Input1->update();
ImageData Input1Data = Input1->getOutput();
switch (Input1Data.PixelType)
{
default:
{
throw std::runtime_error("Type not Supported");
break;
}
case itk::ImageIOBase::RGB:
{
switch (Input1Data.ComponentType)
{
default:
{
throw std::runtime_error("Type not Supported");
break;
}
case itk::ImageIOBase::IOComponentType::UCHAR:
{
using PixelType = itk::RGBPixel< unsigned char >;
using ImageType = itk::Image < PixelType, 2 >;
itk::FlipImageFilter<ImageType>::Pointer filter = itk::FlipImageFilter<ImageType>::New();
//do stuff
break;
}
break;
}
}
}
}
4. The Problem with my Solution
It's working but creates a lot of repetitive code and large nested switch cases. Do you know a more elegant way of solving this problem?
Thank you!
The high level processing you want is:
template <typename PixelType>
void do_stuff()
{
using ImageType = Image < PixelType, 2 >;
...do stuff...
}
You can create one verbose but reusable (by varying the "Fn" code to dispatch to) version of your switching code:
template <typename Fn>
void dispatch(PixelType pt, ComponentTypeId ct, Fn fn) {
switch (pt)
{
case RGB:
switch (ct) {
case Uint8_t: fn(RGBPixel<uint8_t>{}); return;
case Float: fn(RGBPixel<float>{}); return;
};
case RGBA:
switch (ct) {
case Uint8_t: fn(RGBAPixel<uint8_t>{}); return;
case Float: fn(RGBAPixel<float>{}); return;
};
case Scalar:
switch (ct) {
case Uint8_t: fn(ScalarPixel<uint8_t>{}); return;
case Float: fn(ScalarPixel<float>{}); return;
};
}
}
Then, call it like this:
dispatch(runtime_pixel_type, runtime_component_type,
[](auto pt) { do_stuff<decltype(pt)>(); });
Notes:
using a default-constructed "XXXPixel" argument to the lambda is ugly - C++2a is supposed to introduce proper templated lambdas that might (?!) clean this up.
you can chain several "dispatch" functions that each dispatch based on one runtime variable to avoid a multiplicative explosion of switch cases; that scales better but is overkill here, and you'd have to work around PixelType being a template.
you can add your default: throws back in - no need to break (or return) after them as they never return to the following line of code
I have the following use case.
I need to create an Image class. An image is defined by:
the number of pixels (width * height),
the pixel type (char, short, float, double)
the number of channels (single channel, 3 channels (RGB), 4 channels (RGBA)
All combinations of the above types shall be possible.
Furthermore,
I have some algorithms that operate over those images. These algorithms use templates for the pixel type.
I need to interface with totally generic file formats (e.g. TIFF). In these file formats, the pixel data is saved as a binary stream.
My question is the following: should I use a templated Image class, or a generic interface? Example:
// 'Generic' Image interface
class Image {
...
protected:
// Totally generic data container
uint8_t* data;
};
// Template Image interface
template <typename PixelType>
class Image {
...
protected:
// Template data container
PixelType* data;
};
Using Template Image Class
My problem now is that, if I use the templated Imageclass, my file Input/Output will be messy, as when I open an Image file, I don't know a-priori what the Image type will be, so I don't know what template type to return.
This would probably be the optimal solution, if I could figure out a way of creating a generic function that would read an Image from a file and return a generic object, something similar to
ImageType load(const char* filename);
but since ImageType would have to be a template, I don't know how and if I could do this.
Using Generic Image Class
However, if I use a generic Image class, all my algorithms will need a wrapper function with a if/switch statement like:
Image applyAlgorithmWrapper(const Image& source, Arguments args) {
if (source.channels() == 1) {
if (source.type() == IMAGE_TYPE_UCHAR) {
return FilterFunction<unsigned char>(source, args);
}
else if (source.type() == IMAGE_TYPE_FLOAT) {
return FilterFunction<float>(source, args);
} else if ...
} else if (source.channels() == 3) {
if (source.type() == IMAGE_TYPE_UCHAR) {
return FilterFunction<Vec3b>(source, args);
}
...
}
(NOTE: Vec3b is a generic 3 byte structure like
struct Vec3b {
char r, g, b;
};
In my opinion a templated class is the preferred solution.
It will offer you all the advantages of templates which basically mean that your codebase would be cleaner and simpler to understand and maintain.
What you say is a problem when using a templated class is not much of a problem. When a user would like to read an image, he/she should know the data type in which he/she would like to receive the output of the image file. Hence, a user should do it like this :
Image<float>* img;
LoadFromTIFF(*img, <filename>);
This is very similar to the way it is done in libraries such as ITK. In your module which you will perhaps write to read from TIFF module, you will perform this type-casting to ensure that you return the type that has been declared by the user.
When manually creating an image, the user should do something like :
Image<float>*img;
img->SetSize(<width>, <height>);
img->SetChannels(<enum_channel_type>);
It is all much simpler in the long run than having a non-templated class.
You could take a look at the source code of ITK to get an idea of how this can be implemented in the most generic sense, as ITK is a highly templated library.
EDIT (Addendum)
If you do not want the user to have apriori control over the image data type, you should consider using SMinSampleValue and SMaxSampleValue tags in the TIFF header. These headers are there in any modern TIFF file (Version 6.0). They are intended to have a TYPE that matches the sample datatype in the TIFF file. That I believe would solve your problem
To make the right decision (based on facts rather than opinion) about template versus non-template, my strategy is to measure and compare for both solutions (templates and non-templates). I like to measure the following indicators:
number of lines of code
performances
compilation time
as well as other more subjective measures such as:
ease of maintenance
how much time does it take to a freshman to understand the code
I developed a quite large software [1], and based on these measures, my image class is not a template. I know other imaging library that offers both options [2] (but I do not know what mechanisms they have for that / whether the code remains very legible). I also had some algorithms operating with points of various dimensions (2d, 3d, ... nd), and for these ones making the algorithm a template resulted in a performance gain that made it worth it.
In short, to make the right decision, have clear criteria, clear way of measuring them, and try both options on a toy example.
[1] http://alice.loria.fr/software/graphite/doc/html/
[2] http://opencv.org/
Templates. And a variant. And an 'interface helper', if you don't yet have C++14. Let me explain.
Whenever you have a limited set of specializations for a given operation, you can model them as classes satisfying an interface or concept. If these can be expressed as one template class, then do so. It helps your users when they only want a given specialization and all you need is a factory when you read from untyped source (e.g. file). Note that you need a factory anyway, it's just that the return type is well-defined normally. And this is where we come to...
Variants. Whenever you don't know your return type, but you know at compile time the set of possible return types, use a variant. Typedef your variant so it 'looks like' a base class (note that there no inheritance or virtual functions involved), then use a visitor. A particularly easy way to write a visitor in C++14 is a generic lambda that captures everything by reference. In essence, from that point in your code, you have the specific type. Therefore, take the specific/templated classes as function arguments.
Now, a boost::variant<> (or std::variant<> if you have it) cannot have member functions. Either you reside to 'C-API style' generic functions (that are possibly just delegating to the member functions) and symmetric operators; or you have a helper class that's created from your variant type. If your CR allows it, you might descend from variant - note, some consider this terrible style, others accept it as the library writer's intention (because, had the writers wanted to forbid inheritance, they had written final).
Code sketch, do not try to compile:
enum PixelFormatEnum { eUChar, eVec3d, eDouble };
template<PixelFormatEnum>
struct PixelFormat;
template<>
struct PixelFormat<eUChar>
{
typedef unsigned char type;
};
// ...
template<PixelFormatEnum pf>
using PixelFormat_t = typename PixelFormat<pf>::type;
template<PixelFormatEnum pf>
struct Image
{
std::vector<std::vector<PixelFormat_t<pf> > > pixels; // or anything like that
// ...
};
typedef boost::variant< Image<eUChar>, Image<eVec3d>, Image<eDouble> > ImageVariant;
template<typename F>
struct WithImageV : boost::static_visitor<void>
{
// you could do this better, e.g. with compose(f, bsv<void>), but...
F f_;
template<PixelFormatEnum e>
void operator()(const Image<e>& img)
{
f_(img);
}
}
template<typename F>
void WithImage(const ImageVariant& imgv, F&& f)
{
WithImageV v{f};
boost::apply_visitor(v, img);
}
std::experimental::optional<ImageVariant> ImageFactory(std::istream& is)
{
switch (read_pixel_format(is))
{
case eUChar: return Image<eUchar>(is);
// ...
default: return std::experimental::nullopt;
}
}
struct MyFavoritePixelOp : public boost::static_visitor<int>
{
template<PixelFormatEnum e>
int operator()(PixelFormat_t<e> pixel) { return pixel; }
template<>
int operator()(PixelFormat_t<eVec3d> pixel) { return pixel.r + pixel.g + pixel.b; }
};
int f_for_variant(const ImageVariant& imgv)
{
// this is slooooow. Use it only if you have to, e.g., for loading.
// Move the apply_visitor out of the loop whenever you can (here you could).
int sum = 0;
for (auto&& row : imgv.pixels)
for (auto&& pixel : row)
sum += boost::apply_visitor(MyFavoritePixelOp(), pixel);
return sum;
}
template<PixelTypeEnum e>
int f_for_type(const Image<e>& img)
{
// this is faster
int sum = 0;
for (auto&& row : img)
for (auto&& pixel : row)
sum += MyFavoritePixelOp()(pixel);
return sum;
}
int main() {
// ...
if (auto imgvOpt = ImageFactory(is))
{
// 1 - variant
int res = f_for_variant(*imgvOpt);
std::cout << res;
// 2 - template
WithImage(*imgvOpt, [&](auto&& img) {
int res2 = f_for_type(img);
std::cout << res2;
});
}
}
I have a question, though it is not limited to C++. How to return totally different class from one function?
f() {
in case one: return A;
in case two: return B;
in case three: return C;
}
For example, I have two balls in the space, according to the position and the size, there are three situations for the two balls to intersect with each other, i.e, non-intersection, at point, a and circle. How can I return different class in one function?
Thanks.
If you can afford Boost then this sounds like a perfect application for Boost.Variant.
struct NoIntersection {
// empty
};
struct Point {
// whatever
};
struct Circle {
// whatever
};
typedef boost::variant<NoIntersection, Point, Circle> IntersectionResult;
IntersectionResult intersection_test() {
if(some_condition){
return NoIntersection();
}
if(other_condition){
return Point(x, y);
}
if(another_condition){
return Circle(c, r);
}
throw std::runtime_error("unexpected");
}
You then process your result with a static visitor:
struct process_result_visitor : public boost::static_visitor<> {
void operator()(NoIntersection) {
std::cout << "there was no intersection\n";
}
void operator()(Point const &pnt) {
std::cout << "there was a point intersection\n";
}
void operator()(Circle const &circle) {
std::cout << "there was a circle intersection\n";
}
};
IntersectionResult result = intersection_test();
boost::apply_visitor(process_result_visitor(), result);
EDIT: The visitor class must derive from boost::static_visitor
UPDATE: Prompted by some critical comments I've written a little benchmark program. Four approaches are compared:
boost::variant
union
class hierarchy
boost::any
These are the results in my home computer, when I compile in release mode with default optimizations (VC08):
test with boost::variant took 0.011 microseconds
test with union took 0.012 microseconds
test with hierarchy took 0.227 microseconds
test with boost::any took 0.188 microseconds
Using boost::variant is faster than a union and leads (IMO) to the most elegant code. I'd guess that the extremely poor performance of the class hierarchy approach is due to the need to use dynamic memory allocations and dynamic dispatch. boost::any is neither fast nor especially elegant so I wouldn't consider it for this task (it has other applications though)
The classes you want to return should be derived from a common base class. So, you can return the base type. For Example (this is not a code, just marking the pattern, you can use an interface if your language supports this abstraction or abstract class for example. If you use C++ you will have to return a pointer of the common class):
class A : public Common
{
..
}
class B : public Common
{
..
}
class C : public Common
{
..
}
Common f() {
in case one: return A;
in case two: return B;
in case three: return C;
}
In addition to #Manuel's Boost.Variant suggestion, take a look at Boost.Any: has similar purpose as Boost.Variant but different tradeoffs and functionality.
boost::any is unbounded (can hold any type) while boost::variant is bounded (supported types is encoded in variant type, so it can hold only values of these types).
// from Beyond the C++ Standard Library: An Introduction to Boost
// By Björn Karlsson
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "boost/any.hpp"
class A {
public:
void some_function() { std::cout << "A::some_function()\n"; }
};
class B {
public:
void some_function() { std::cout << "B::some_function()\n"; }
};
class C {
public:
void some_function() { std::cout << "C::some_function()\n"; }
};
int main() {
std::cout << "Example of using any.\n\n";
std::vector<boost::any> store_anything;
store_anything.push_back(A());
store_anything.push_back(B());
store_anything.push_back(C());
// While we're at it, let's add a few other things as well
store_anything.push_back(std::string("This is fantastic! "));
store_anything.push_back(3);
store_anything.push_back(std::make_pair(true, 7.92));
void print_any(boost::any& a);
// Defined later; reports on the value in a
std::for_each(
store_anything.begin(),
store_anything.end(),
print_any);
}
void print_any(boost::any& a) {
if (A* pA=boost::any_cast<A>(&a)) {
pA->some_function();
}
else if (B* pB=boost::any_cast<B>(&a)) {
pB->some_function();
}
else if (C* pC=boost::any_cast<C>(&a)) {
pC->some_function();
}
}
In order to be able to do anything useful with the result, you have to return an object which has a common baseclass. In your case you might want to let A, B, and C inherit from a common "intersection-class"; a class which is common for all objects which represents some form of intersection. Your function f would then return an object of this type.
The classes you want to return should have a common parent class or interface.
If those classes do not have anything in common, that, I suppose, is untrue, you can return object.
This feature is also known as polymorphism.
In c++ base class pointer can point to derived class object. We can make use of this fact to code a function that meets your requirements:
class shape{};
class circle: public shape
{};
class square: public shape
{};
shape* function(int i){ // function returning a base class pointer.
switch(i) {
case 1: return new circle();
case 2: return new square();
}
}
There is one other option available. You can return a union of pointers to objects along with a tag that tells the caller which member of the union is valid. Something like:
struct result {
enum discriminant { A_member, B_member, C_member, Undefined } tag;
union result_data {
A *a_object;
B *b_object;
C *c_object;
} data;
result(): tag(Undefined) {}
explicit result(A *obj): tag(A_member) { data.a_object = obj; }
explicit result(B *obj): tag(B_member) { data.b_object = obj; }
explicit result(C *obj): tag(C_member) { data.c_object = obj; }
};
I would probably use Boost.variant as suggested by Manuel if you have the option.
You can't. You can only return a base pointer to different derived classes. If this is absolutely, 100% needed, you can use exceptions as a ugly hack, but that's obviously not recommended at all.
Even if you could return three different types of objects from the function, what would you do with the result? You need to do something like:
XXX ret_val = getIntersection();
If getIntersection returned three different types of objects, XXX would have to change based on what getIntersection was going to return. Clearly this is quite impossible.
To deal with this, you can define one type that defines enough to cover all the possibilities:
class Intersection {
enum { empty, point, circle, sphere};
point3D location;
size_t radius;
};
Now getIntersection() can return an Intersection that defines what kind of intersection you have (and BTW, you need to consider the fourth possibility: with two spheres of the same radius and same center point, the intersection will be a sphere) and the size and location of that intersection.
The limitation is based on the declared return type of your method. Your code states:
f() {
in case one: return A;
in case two: return B;
in case three: return C;
}
When in reality the compiler requires something like this:
FooType f() {
in case one: return A;
in case two: return B;
in case three: return C;
}
It must be possible to convert the A, B, and C to a FooType, typically through simple inheritance, though I won't get into the differences between subclasses vs subtyping.
There are approaches that can get around this. You could create a class or struct (C++) which has fields for each different type of possible return and use some flag field to indicate which field is the actual returned value.
class ReturnHolder {
public int fieldFlag;
public TypeA A;
public TypeB B;
public TypeC C;
}
The enum example in another answer is more of the same. The reason why that is a hack is that the code that handles the return from this method will have to have lots of code to handle each of the different possibilites, like so
main(){
FooType *x = new FooType();
ReturnHolder ret = x.f();
switch (ret.fieldFlag)
case: 1
//read ret.A
case: 2
//read ret.B
case: 3
//read ret.C
}
And that's without even going into trying to do it with Exceptions which introduce even bigger problems. Maybe I'll add that in later as an edit.
And by the way, as you said that question "is not limited to C++":
1) dynamic languages, of course, make it piece of cake:
# python
def func(i):
if i == 0:
return 0
elif i == 1:
return "zero"
else
return ()
2) some functional languages (Haskell, OCaml, Scala, F#) provide nice built-in variants that are called Algebraic Data Types (article has good samples).
In languages that reflection, it is easier to achieve. In cpp, if you have a standard set of classes to be returned (pointers), create an enumeration and return the enum value. Using this value you can infer the class type. This is a generic way in case there is no common parent class
You really shouldn't want to be doing that, and should really come up with a better design instead of forcing a square peg in a round hole. And with most languages you can't do it at all, by design. You will never really know what you are working with, and neither will the compiler ahead of time, ensuring extra bugs and weird behavior and incomprehensibility.
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: //...
//...
}
}
Original C++03 answer:
The benefit from a namespace (over a class) is that you can use using declarations when you want.
The problem with using a namespace is that namespaces can be expanded elsewhere in the code. In a large project, you would not be guaranteed that two distinct enums don't both think they are called eFeelings
For simpler-looking code, I use a struct, as you presumably want the contents to be public.
If you're doing any of these practices, you are ahead of the curve and probably don't need to scrutinize this further.
Newer, C++11 advice:
If you are using C++11 or later, enum class will implicitly scope the enum values within the enum's name.
With enum class you will lose implicit conversions and comparisons to integer types, but in practice that may help you discover ambiguous or buggy code.
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 { ... };
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: ... ;
}
}
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: //...
//...
}
}
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:
prohibit (sadly, not compile-time) C++ from allowing a cast from invalid value,
set a (non-zero) default for newly-created enums,
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.
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!
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.
I also tend to wrap my enums in classes.
As signaled by Richard Corden, the benefit of a class is that it is a type in the c++ sense and so you can use it with templates.
I have special toolbox::Enum class for my needs that I specialize for every templates which provides basic functions (mainly: mapping an enum value to a std::string so that I/O are easier to read).
My little template also has the added benefit of really checking for the allowed values. The compiler is kind of lax on checking if the value really is in the enum:
typedef enum { False: 0, True: 2 } boolean;
// The classic enum you don't want to see around your code ;)
int main(int argc, char* argv[])
{
boolean x = static_cast<boolean>(1);
return (x == False || x == True) ? 0 : 1;
} // main
It always bothered me that the compiler will not catch this, since you are left with an enum value that has no sense (and that you won't expect).
Similarly:
typedef enum { Zero: 0, One: 1, Two: 2 } example;
int main(int argc, char* argv[])
{
example y = static_cast<example>(3);
return (y == Zero || y == One || y == Two) ? 0 : 1;
} // main
Once again main will return an error.
The problem is that the compiler will fit the enum in the smallest representation available (here we need 2 bits) and that everything that fits in this representation is considered a valid value.
There is also the problem that sometimes you'd rather have a loop on the possible values instead of a switch so that you don't have to modify all you switches each time you add a value to the enum.
All in all my little helper really ease things for my enums (of course, it adds some overhead) and it is only possible because I nest each enum in its own struct :)