Can I force-initialize all possible enum values ββof the class template / function of the enum class?
I have template class
using a parameter enum class
as a template defined in a header file:
// MyClass.h
enum class MyEnum {FOO, BAR};
template<MyEnum T>class MyClass {
void doStuff();
// ...
};
I would like to have the actual implementations of the member functions in a separate source file. I know that in this case I have to provide template initialization for each case:
//MyClass.cpp
template<MyEnum T>void MyClass<T>::doStuff() {
// ...
}
// Implementations of other functions
template class MyClass<MyEnum::FOO>;
template class MyClass<MyEnum::BAR>;
Generally, I know that I want a class with all possible values ββfor enum
anyway, so I would like to tell the compiler that it should actually construct a template class for every possible value without explicitly mentioning every possibility.
In other words: I want to replace the last two lines in the example with some automatic code.
Is it possible?
I would also like to do the same with template functions instead of template class.
source to share
The usual way to tell the compiler about all possible specializations is to implement them in a single file. I can't think of a sane way to tell the compiler that the template class is specialized for every value in the domain.
If you have a bazillion of them, you might want to consider using a macro macro . Isolate all your cases in a header file (say MyEnum.h
) like this:
#ifndef HANDLE_ENUM_CASE(e)
#define HANDLE_ENUM_CASE(e)
#endif
HANDLE_ENUM_CASE(FOO)
HANDLE_ENUM_CASE(BAR)
// add more HANDLE_ENUM_CASE(...) expressions for every other case you have
#undef HANDLE_ENUM_CASE
In the source file, you can:
enum class MyEnum {
#define HANDLE_ENUM_CASE(e) e,
#include "MyEnum.h"
}
// (class declaration here)
#define HANDLE_ENUM_CASE(e) template class MyClass<MyEnum::e>;
#include "MyEnum.h"
source to share
In the old days, when enum was just custom names for integer values, this was trivial: we just added the MAX value as the last enum and repeated with a simple one for (int i=0; i<MAX; i++)
.
If you were using a simple one enum MyEnum { FOO, BAR };
, you could at least overlay MyEnum on an int (but not the other way around) it would be too easy). But when enum class MyEnum { FOO, BAR };
casting to int also undefined.
So the only way to list C ++ 11 is ... the macros way suggested by zneak ... sniff: - (
If you don't like it ( I don't ) you should forget enum class
and use plain integers, or at least like a typedef. And that's not all, the non-type template argument must be a constant expression, so you should also forget the non-type template construct.
This will lead to:
namespace MyEnum {
typedef int MyEnum_t;
enum MyEnum : MyEnum_t { FOO, BAR, MAX };
}
class MyClass {
MyEnum::MyEnum_t T;
public:
MyClass(MyEnum::MyEnum_t t): T(t) {}
void doStuff() {
std::cout << T << std::endl;
}
};
You should probably declare a copy constructor that makes sure you only copy compatible types, because the compiler can no longer control it. But at least you could do:
for(MyEnum::MyEnum_t e=0; e<MyEnum::MAX; e++) {
MyClass obj(e);
obj.doStuff();
}
BTW, since it MyClass
won't be a template anymore, you can feel free to put the actual implementations of member functions in a separate source file ...
source to share