I have a program in which I would like to choose a set of types (from predefined lists) at run time, not compile time.
Below is an example of the kind of code I'd like to run; Even
and Log
are types to define a numerical grid, and deriv_Ox
is a differentiation scheme of order x:
struct Even {
double a, b;
};
struct Log {
double a, x0, b;
};
// ...
struct deriv_O2 {
vec_type operator() (const vec_type & f_points) const;
};
struct deriv_O4 {
vec_type operator() (const vec_type & f_points) const;
};
// ...
template <class grid_type, class deriv_type>
void run_calculation (const std::string param_file) {
auto grid = grid_from_file<grid_type>(param_file);
auto deriv = deriv_from_file<deriv_type>(param_file);
// ...
}
I would like to decide which of these types to use at run time, by reading a parameter file. My solution was to use tags and case statements to decide which type to use from a single list, then nest each case statement in a function deciding each type in the set as follows:
enum struct grid_tag { Even, Log };
enum struct deriv_tag { O4, O2 };
grid_tag grid_tag_from_file (const char file_name[]);
deriv_tag deriv_tag_from_file (const char file_name[]);
template <class deriv_type>
void run_calculation (const grid_tag g,
const std::string param_file) {
switch(g) {
case grid_tag::Even:
run_calculation<Even, deriv_type>(param_file);
break;
case grid_tag::Log:
run_calculation<Log, deriv_type>(param_file);
break;
}
}
void run_calculation (const grid_tag g, const deriv_tag d,
const std::string param_file) {
switch(d) {
case deriv_tag::O4:
run_calculation<deriv_O4>(g, param_file);
break;
case deriv_tag::O2:
run_calculation<deriv_O2>(g, param_file);
break;
}
}
int main (int argc, char * argv[]) {
grid_tag g = grid_tag_from_file(argv[1]);
deriv_tag d = deriv_tag_from_file(argv[1]);
run_calculation(g, d, argv[1]);
}
The problem is that I have a set of ~6 types to choose from lists of size ~10, and these will grow in the future. The solution I have at the moment makes adding new types awkward.
Is this solution the best I'm going to do? Am I being very fussy, or is there a better solution someone can suggest? I have looked at boost::variant (as recommended in similar questions) but I don't think this is really suitable for what I want to do.