choose correct template specialization at run-time

此生再无相见时 提交于 2019-12-22 06:51:32

问题


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.


回答1:


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).




回答2:


You have to. Templates are resolved and instantiated at compile-time. Apart from that, a switch needn't be inefficient. It usually compiles to a lookup table with very little overhead.

You can, however, use recursive template magic to have nested if/else blocks to replace the switch generated for you by the compiler. But a plain switch should be much more readable. Unless of course you have literally thousands of cases.

In either case, you need to know the set of values that i can have at compilation time since the compiler needs to know which templates to instantiate.




回答3:


You can't pick a template specialization at runtime, they're by definition chosen at compile time.

The usual ways to solve the dispatch problem you're looking at are switch (as you surmised) or a vector or map of int to function pointer.




回答4:


No, compiler needs to the instantiation of the template at compile time, for that it needs to know the value of i at compile time.




回答5:


You can't as template instantiation is done at compile time.



来源:https://stackoverflow.com/questions/5621810/choose-correct-template-specialization-at-run-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!