5

我有

template <int i> struct a { static void f (); };

在代码中的不同位置进行专业化。我如何才能在运行时调用正确a<i>::fi已知值?

void f (int i) { a<i>::f (); } // won't compile

我不想i在一个大的switch.

编辑:

我想到了类似的东西

#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);
}

但它崩溃了(我错过了强制实例化的东西吗?),我不喜欢那个 dummy 不是static const(并且使用内存),当然这arrsize比必要的要大。


实际问题:只有在运行时generate (int i)调用为给定a<i>::generate ()生成类实例的函数。设计(类)是给定的,它们继承自基类,并且可以随时在代码中的任何地方添加更多的专业化,但我不想强迫每个人手动更改我的,因为这很容易被忘记。a<i>ia<i>generate (i)

4

5 回答 5

5

我不确定这是否是您可以获得的最佳解决方案,因为可能会有更好的设计,无论如何您可以使用一些元编程来触发函数的实例化和注册:

// 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
}

该代码将实例化函数并注册指向静态成员函数的指针。假返回类型需要能够在静态上下文中强制执行函数(通过使用该函数来初始化静态值)。

这很容易导致静态初始化失败。虽然没regf::v问题,但任何依赖于regf::v在静态初始化期间包含适当指针的代码都必然会失败。您可以使用通常的技术来改进它...

从您实际发布的点点滴滴来看,我的猜测是您正在尝试使用一个抽象工厂,并从每个具体工厂自动注册。有更好的方法来解决这个问题,但我认为这个答案解决了你的问题(我不确定这是否能解决你的问题)。

于 2011-04-11T15:55:17.607 回答
4

你必须。模板在编译时被解析和实例化。除此之外,aswitch不一定是低效的。它通常编译成一个查找表,开销很小。

但是,您可以使用递归模板魔术来使用嵌套if/else块来替换switch编译器为您生成的块。但是平原switch应该更具可读性。当然,除非你有成千上万的案例。

在任何一种情况下,您都需要知道i编译时可以具有的值集,因为编译器需要知道要实例化哪些模板。

于 2011-04-11T13:12:08.917 回答
2

您不能在运行时选择模板专业化,它们是在编译时根据定义选择的。

解决您正在查看的调度问题的常用方法是switch(如您所推测的)或函数vector指针。mapint

于 2011-04-11T14:04:46.643 回答
1

不,编译器需要在编译时实例化模板,因为它需要i在编译时知道 的值。

于 2011-04-11T13:13:26.623 回答
1

你不能因为模板实例化是在编译时完成的。

于 2011-04-11T13:34:25.857 回答