【问题标题】:Explicit Instantiation for Variadic Template Functions可变参数模板函数的显式实例化
【发布时间】:2014-10-31 03:35:03
【问题描述】:

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

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

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

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

int 参数的最大数量是非常量 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() 的返回值的情况下,有什么方法可以正确地做到这一点?

【问题讨论】:

  • 看来这可能是不可能的,编译器(特别是 gcc)如何使用省略号和 va_list 处理 C 风格的变量参数函数的代码生成?例如:void func(int a, ...) { ... }

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


【解决方案1】:

不,您不可能在编译时生成依赖于仅在运行时才知道的值的模板。您将需要提前选择一个常数的最大值(有时不使用所有实例化),或者想办法使 maxArgs() 成为编译时常数。或者在使用时即时编译您的代码!

由于您对这段代码的了解比我们多,也许您可​​以考虑是否真的需要将其设为可变参数模板。鉴于模板参数的数量是在运行时确定的,这似乎不是。编写一个完全由运行时确定的解决方案可能会更好,没有可变参数模板的东西。

【讨论】:

  • 所以我需要以这种方式生成代码的原因是因为我必须为func的各种实例提供另一个库函数指针,不知道将使用哪些具体实例由应用程序使用我自己的库。另外,我传递函数指针的库负责maxArgs()
  • maxArgs() 的允许范围是多少?就您需要如何为其提供函数指针而言,其他库的确切要求是什么?它可以接受指向 C 风格的可变参数函数(如 printf)的指针,还是需要指向带有 1..maxArgs 参数的常规函数​​的指针?如果是后者,那么如何正确使用此类库?似乎很难想象。
  • 可能的范围是8 &lt;= maxArgs() &lt;= 42。该库以函数指针数组的形式获取函数,其中类型必须类型转换为void (*fn)();这些函数不需要模板,可以使用 C 风格的可变参数函数
  • @AlexBrooks:那么看来您应该为所有不超过 42 的值实例化您的函数模板并完成它。如果库调用您的函数时第一个参数是后面参数的数量,您可以编写一个非模板的 printf 样式函数。就目前而言,我对您正在使用的这个库的设计感到惊讶:它似乎旨在迷惑它的用户。
  • 谢谢。有关更多上下文,该库是 GASNet,而我所描述的库的一部分是围绕其活动消息功能的包装器(出于各种原因)。
【解决方案2】:

由于我知道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;
}

【讨论】:

    猜你喜欢
    • 2014-09-13
    • 2014-06-30
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 2011-06-23
    相关资源
    最近更新 更多