I have a class depending on an integer template parameter. At one point in my program I want to use one instantiation of this template, depending on a value of this parameter determined at runtime. Here is a simple example demonstrating how I would go about this currently, using a big switch statement:
#include <string>
#include <iostream>
#include <type_traits>
template<unsigned A>
struct Wrapper {
typedef typename std::conditional<A==1, int, float>::type DataType;
DataType content[A];
void foo() {
std::cout << A << std::endl;
};
};
int main(int argc, char *argv[])
{
std::string arg = argv[1];
int arg_int = std::stoi(arg);
switch (arg_int) {
case 1: {
Wrapper<1> w;
w.foo();
break;
}
case 2: {
Wrapper<2> w;
w.foo();
break;
}
case 3: {
Wrapper<3> w;
w.foo();
break;
}
default:
return 1;
};
return 0;
}
This will quickly get unwieldy once I have not only one parameter A
, but multiple template arguments in various combinations. Let's also assume that in reality there is a really good reason to implement A as a template parameter.
Is there a way to replace the huge switch statement with almost identical case statements, e.g. using some metaprogramming magic from Boost or a preprocessor hack?
Ideally I would like to be able write something like the following:
INSTANTIATE_DEPENDING(i, {1, 2, 3},
{
Wrapper<i> w;
w.foo();
}
);
You could use a variadic template, maybe like this:
#include <cstdlib>
#include <string>
int main(int argc, char * argv[])
{
if (argc != 2) { return EXIT_FAILURE; }
handle_cases<1, 3, 4, 9, 11>(std::stoi(argv[1]));
}
Implementation:
template <int ...> struct IntList {};
void handle_cases(int, IntList<>) { /* "default case" */ }
template <int I, int ...N> void handle_cases(int i, IntList<I, N...>)
{
if (I != i) { return handle_cases(i, IntList<N...>()); }
Wrapper<I> w;
w.foo();
}
template <int ...N> void handle_cases(int i)
{
handle_cases(i, IntList<N...>());
}