shu shu - 26 days ago 11
C++ Question

Associating enums with template classes at compile time

I have a template class as below:

template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };

template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}


and I have an object that has a collection of these classes:

using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;

class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}


I want to know if it is possible to define an enum list:

enum TaskEnum
{
Etask1,
Etask2
};


and a function
getTask
such that in my app I can have:

int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}


I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?

Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.

Answer

You can always template a concrete class with primitives. So instead of:

using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;

you can just have

template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}

and then define a template function:

template<TaskEnum taskE>    
Task<taskE>* getTask() {}

You will need to derive template class Task from a base class so you can put it in a map, and you should define a map

std::map<TaskEnum,TaskBase*>    taskMap;

and in getTask you can just do a static cast:

static_cast<Task<taskE>* >(taskBasePtr);
Comments