We have
enum Enum {A,B,C,D,E,F,G,H, NumEnums};
class Base {};
template <Enum...> class Thing : public Base {};
and the function
Base* create (std::list<Enum>& input);
is to create an object of the type that corresponds to input. For example,
if input = {A,E,C,G,D};, then the output shall be of type Thing<A,E,C,G,D>* (let's forget the sorting here). Now I know input is obtained during run-time, but by doing a search, the output can be obtained fairly quickly. If Thing had only one parameter (i.e. input has size() one), then the simple
template <int N>
Base* createHelper (const std::list<Enum>& input) {
const Enum En = static_cast<Enum>(N);
if (input.front() == En)
return new Thing<En>;
return createHelper<N+1>(input);
}
template <>
Base* createHelper<NumEnums> (const std::list<Enum>&) {
return nullptr;
}
Base* create (const std::list<Enum>& input) {
return createHelper<0>(input);
}
will do. I tried to generalize the above to any size list (the size would have to be determined during run-time through a similar recursion as above, but that should be fairly quick too). But I got totally lost on how. So I tried to examine the structure of the naïve method:
#include <iostream>
#include <list>
#include <type_traits>
#include <typeinfo>
enum Enum {A,B,C,D,E,F,G,H, NumEnums};
class Base {
public:
virtual void print() const = 0;
};
template <Enum...> class Thing : public Base {
virtual void print() const override {std::cout << typeid(*this).name() << '\n';}
};
Base* create (std::list<Enum>& input) {
if (input.front() == A) {
input.pop_front();
if (input.empty())
return new Thing<A>;
else {
if (input.front() == A) {
input.pop_front();
if (input.empty())
return new Thing<A,A>;
else {
// ....
}
}
else if (input.front() == B) {
input.pop_front();
if (input.empty())
return new Thing<A,B>;
else {
// ....
}
}
}
}
else if (input.front() == B) {
// similar
}
// ...
}
int main() {
std::list<Enum> userInput = {A,B};
// Wish to construct an instance of Thing<A,B> (efficiently).
Base* thing = create(userInput);
thing->print(); // Thing<A,B>
}
I figured I could put this in recursive form. But I cannot think of it. I know the one-dimensional case can be generalized, but I need help here. Or perhaps there is a better way to do it altogether? Once it works, it should not take anymore than a fraction of a second for the create function to return, assuming NumEnums is a decent size and the Thing class has just several template arguments, and not hundreds.
Thinginstantiations need to be known at compile time and thus you can't sort this out at runtime for a general list. You can do transformations like this usingboost::mplstyle type-lists as the "list" then has the type information of interest at compile time.