具有类型名的模板的递归实例化

Recursive instantiation of a template with a typename?

本文关键字:递归 实例化 类型      更新时间:2023-10-16

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

#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 %in", 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必须位于函数内部,因为函数本身是模板化的。

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

因此,您需要一种方法来在函数外部声明它。

事实证明,宏

是邪恶的,只需将宏重写为模板即可使一切正常工作。

#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 实现,例如从这里。尝试在没有它的情况下实现嵌套的部分专用结构是混乱的,因为您无法在模板内专门化功能。