Variadic模板函数的显式实例化

时间:2014-09-06 08:37:06

标签: c++11 code-generation instantiation variadic-templates

我正在编写一个使用可变模板函数的库,如下所示:

template<typename ... T>
void func(T ... args) {
  // ...
}

我需要确保为某些类型的函数生成代码(即显式实例化),如下所示:

template class func<int>;
template class func<int, int>;
template class func<int, int, int>;
// ...

其中int个参数的最大数量是非const maxArgs()(我无法更改它,因为它是一个外部函数)。我尝试过以下方法:

template<typename ... T>
void f(size_t max, T ... args) { // Generates "infinitely"
  if (sizeof...(T) < max) {
    func(args...);
    f(max, args..., 0);
  }
}

int main(int argc, char** argv) {
  f(maxArgs(), 0);
  // ...
  return 0;
}

但是编译器没有适当的函数生成递归的基本情况,因此无法编译。我也尝试使用非类型模板(使用here中的一些代码):

template<int ...> struct seq { };
template<int N, int ... Ns> struct gens : gens<N-1, N-1, Ns...> { };
template<int ... Ns> struct gens<0, Ns...> { typedef seq<Ns...> type; };

std::vector<int> params;

template<int ... Ns>
void f(seq<Ns...>) {
  test(std::get<Ns>(params)...);
}

void instantiate(size_t max) {
  for (int i = 1; i < max; ++i) {
    for (int j = 0; j < i; ++j) {
      params.push_back(0);
    }
    f(typename gens<i>::type()); // Fails to compile -- i is not const
    params.clear();
  }
}

int main(int argc, char** argv) {
  instantiate(maxArgs());
}

但这需要一个const值,所以它也无法编译。有没有办法在不知道maxArgs()的返回值的情况下正确地做到这一点?

2 个答案:

答案 0 :(得分:1)

不,您不可能在编译时生成依赖于仅在运行时已知的值的模板。您需要选择一些提前保持常量的最大值(有时不使用所有实例化),或者找出一种方法使maxArgs()成为编译时常量。或者在使用它时动态编译代码!

由于您获得的信息比我们对此代码的信息要多,或许您可以考虑是否真的需要将其作为可变参数模板。考虑到在运行时确定模板参数的数量,似乎不是这样。编写完全运行时确定的解决方案可能会更好,而不需要可变参数模板。

答案 1 :(得分:0)

因为我知道maxArgs()(即42)的最大可能值,所以我想出了以下解决方案,感谢@JohnZwinck的建议。

#include <vector>

typedef void (*void_fnptr)();

std::vector<void_fnptr> table;

// Function that needs to be code-generated for certain number of int types
template<typename ... T>
void func(T ... args) {
  // ...
}

template<typename T>
void instantiate(T elem) {
  table.push_back((void_fnptr)func<T>);
}

template<typename T, typename ... Ts>
void instantiate(T first, Ts ... rest) {
  table.push_back((void_fnptr)func<T, Ts...>);
  instantiate(rest...);
}

int main(int argc, char** argv) {
  // 42 int arguments:
  instantiate(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
              0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  // ...
  return 0;
}