2017-04-14 82 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-有到把最模板和類型名稱的關鍵字) –