使用typename递归实例化模板?

时间:2017-04-14 14:07:12

标签: c++ templates

对于带整数的模板化函数,我编写了以下通用调度程序:

#define Dispatch_Template(funct_name, max) \
  template<int i> decltype(&funct_name<0>) Dispatch_template_##funct_name (int index) {     \
    return (index == i) ? funct_name <i> : Dispatch_template_##funct_name <i - 1>(index);   \
  } \
  template<> decltype(&funct_name<0>) Dispatch_template_##funct_name <-1>(int) {            \
    return nullptr;                                                                         \
  }                                                                                         \
  decltype(&funct_name<0>) Dispatch_##funct_name (int i) {                                  \
    return Dispatch_template_##funct_name <max>(i);                                         \
  }                                                                                         \

这有效,我可以这样做:

template<int some_int> void PrintInt() {
  printf("int is %i\n", some_int);
}

Dispatch_Template(PrintInt, 6);

int main()
{
  for (int i = 0; i < 6; ++i) {
    Dispatch_PrintInt(i)();        
  }
 return 0;
}

但是如果我想将typename参数传递给我的模板化函数呢?

例如,说它看起来像这样:

template<int some_int, typename some_type> void PrintSomeType(some_type arg) {
  // do something
}

我希望能够做到这一点:

template<typename some_type> void caller(some_type arg) {
  Dispatch_Template(PrintSomeType, some_type, 6);
  for (int i = 0; i < 6; ++i) {
    Dispatch_PrintSomeType(i)(arg);
  }
}

我不知道该怎么做 - 我遇到了“这里不允许模板声明”的问题。 (注意,Dispatch_Template必须在函数内部,因为函数本身是模板化的。)

1 个答案:

答案 0 :(得分:2)

您无法在函数内部使用声明,因为块范围中不允许使用模板。这是一个死胡同。

所以你需要一种方法在函数之外声明它。

事实证明,宏是邪恶的,只是重写宏作为模板使一切正常。

#include <utility>
#include <assert.h>       
#include <iostream>

template<template<int, typename...> class func, typename... Ts>
class Dispatcher {
public:
  using function_ptr = decltype(&func<0, Ts...>::call);

  template<int max=10>
  static function_ptr get_func(int i) {
      assert(i>=0 && i<max);
      return get_func_impl(i, std::make_integer_sequence<int, max>());
  }

private:
  template<int... vals>
  static function_ptr get_func_impl(int i, std::integer_sequence<int, vals...> ) {
      static constexpr function_ptr funcs[] = {&func<vals, Ts...>::call...};
      return funcs[i];
  }

};

template <int i, typename T>
struct Foo {
    static void call(T val) {
        std::cout << "Hello foo " << i << " " << val << std::endl;
    }
};

int main() {
    Dispatcher<Foo, double>::get_func<>(5)(2.3); // output: Hello foo 5 2.3
}

最后一步是为所需的template <...> struct X { call(); };格式创建一个宏。这是必需的,因为您无法将模板函数传递到模板中。

注意:std :: integer_sequence只是c ++ 14,但你可以添加一个polyfill实现,例如来自here。试图在没有它的情况下实现是混乱的嵌套的部分专用结构,因为你不能专门化模板内的函数。