2017-04-14 37 views
1

对于一个模板函数,它接受一个整数,我写了下面的通用调度员:带有typename的模板的递归实例化?

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

+0

C++模板不能在函数体中声明。这就是扩展Dispatch_Template宏所做的事情。我觉得你正在寻找一个非常复杂的解决方案来解决一个简单的问题。如果您描述了您在宏伟计划中想实现的目标,我可以提出一个更简单的解决方案。一般情况下,宏比大多数时候都要麻烦。 – Ghostrider

+0

@Ghostrider我要寻找更好的方法来做到这一点: '模板无效本功能(T VAR){...}' 然后 '如果(我== 0)本功能<0>(VAR);'' 否则如果(I == 1)本功能<1>(VAR);' '...' '否则如果(I == 100)本功能<100>(VAR): ' 我不能从函数本身中删除模板,但我不想明确地输出每个可能的情况。 –

+0

似乎约瑟夫的答案会给你你需要的东西。 – Ghostrider

回答

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。试图在没有它的情况下实现嵌套的部分专用结构会很麻烦,因为你不能在模板中专门化函数。

+0

谢谢!我花了一段时间,但我的代码使用你的例子工作。对于其他人可能会这样做的说明:请记住,您可能需要使用“typename”和“template”关键字来使您的代码无歧义(尤其是当错误消息指示编译器将您的模板代码视为更大 - 符号)。 [这是什么帮助我弄明白了。](http:// stackoverflow。COM /问题/ 610245 /那里,和为什么-DO-I-有到把最模板和类型名称的关键字) –