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.

+3


source to share


2 answers


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"

      

+1


source


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

0


source







All Articles