I have
template <int i> struct a { static void f (); };
with specializations done at different places in the code. How can I call the correct a<i>::f
for an i
known only at runtime?
void f (int i) { a<i>::f (); } // won't compile
I don't want to list all possible values of i
in a big switch
.
Edit:
I thought of something like
#include <iostream>
template <int i> struct a { static void f (); };
struct regf {
typedef void (*F)();
enum { arrsize = 10 };
static F v[arrsize];
template < int i > static int apply (F f) {
static_assert (i < arrsize, "");
v[i] = a<i>::f;
return 0;
}
};
regf::F regf::v[arrsize];
template <int i> struct reg { static int dummy; };
template <int i> int reg<i>::dummy = regf::apply<i> ();
void f (int i) { return regf::v[i] (); }
#define add(i) \
template <> struct a<i> : reg<i> { \
static void f () { std::cout << i << "\n"; } \
};
add(1)
add(3)
add(5)
add(7)
int main () {
f (3);
f (5);
}
but it crashes (did I miss something to force an instantiation?), and I don't like that dummy is not static const
(and uses memory) and of course that arrsize
is bigger than necessary.
Actual problem: To have a function generate (int i)
that calls a<i>::generate ()
to generate an instance of class a<i>
for an i
given only at run-time. The design (classes a<i>
) is given, they inherit from a base class and more specializations of a could be added at any time anywhere in the code, but I don't want to force everyone to change my generate (i)
manually as that could be forgotten easily.
Runtime templates are sometimes called "preprocessed text templates" because at compile time, the template generates code that is executed at run time. Each template is a mixture of the text as it will appear in the generated string, and fragments of program code.
It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.
C++ does not support run-time resolution of template type arguments. To circumvent this restriction, we can instantiate a template for all possible combinations of type arguments at compile time and then select the proper instance at run time by evaluation of some provided conditions.
There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.
I am not sure that this is the best solution that you can get, as there might be better designs, at any rate you can use some metaprogramming to trigger the instantiation and registry of the functions:
// in a single cpp file
namespace {
template <unsigned int N>
int register_a() { // return artificially added
register_a<N-1>(); // Initialize array from 0 to N-1
regf::v[N] = &a<N>::f; // and then N
return N;
}
template <>
int register_a<0>() {
regf::v[0] = &a<0>::f; // recursion stop condition
return 0;
}
const int ignored = register_a<regf::arrsize>(); // call it
}
That code will instantiate the functions and register pointers to the static member functions. The fake return type is required to be able to force execution of the function in an static context (by means of using that function to initialize a static value).
This is quite prone to the static initialization fiasco. While regf::v
is ok, any code that depends on regf::v
containing the appropriate pointers during static initialization is bound to fail. You can improve this with the usual techniques...
From the bits and pieces that you have actually posted, my guess is that you are trying to use an abstract factory with automated registration from each one of the concrete factories. There are better ways of approaching the problem, but I think that this answer solves your question (I am unsure on whether this does solve your problem).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With