2014-09-01 52 views
3

我有getId()模板函數,它可以像getId<SomeType>()getId< Some<NestedType>>()一樣使用。我必須以某種方式區分它們。將模板參數區分爲嵌套模板

template<typename TRequest> 
ParameterId getId() // #1 
{ 
    return tEParameterId_None; 
} 

template<template <class> class TRequest, class TType> 
ParameterId getId() // #2 
{ 
    return TType::paramId; 
} 

template<TRequest<TType>> 
ParameterId getId() // #3, not working 
{ 
    return TType::paramId; 
} 

ParameterId none = getId<SomeType>();     // #1 will be called 
ParameterId still_none = getId<Some<NestedType>>();  // #1 will be called, but I want #3 
ParameterId some_other = getId<SomeType, NestedType>(); // #2 will be called 

我的問題是,我怎麼可以指定#3 getId()模板功能,即getId< Some <NestedType> >()調用究竟3D變形?或者哪個編譯時模板魔法可以區分嵌套模板?

因爲使用了像Some<NestedType>這樣的整個代碼符號,並且我不想改變它並像getId< SomeType, NestedType >()那樣調用 - 它會不一致。

回答

3

您可以使用自定義類型的特徵來檢測,如果一個類型是一個模板:

template <class> 
struct is_template : std::false_type {}; 

template <template <class...> class T, typename ...Args> 
struct is_template<T<Args...>> : std::true_type {}; 

並使用std::enable_if選擇正確的過載(啓用如果該類型是一個模板過載,否則啓用其他):

template<class T> 
typename std::enable_if<is_template<T>::value, int>::type getId() // #1 
{ 
    std::cout << "#1"; 
    return 42; 
} 

template<class T> 
typename std::enable_if<!is_template<T>::value, int>::type getId() // #2 
{ 
    std::cout << "#2"; 
    return 42; 
} 

用法:

int main() 
{ 
    getId<int>();    // Calls #2 
    getId<std::vector<int>>(); // Calls #1 
} 

Live Demo

+0

謝謝你,就像我的一個魅力! – yudjin 2014-09-02 06:13:01

3

這將遞歸應用您的規則,展開模板,直到你得到一個非模板參數:

template<class T> 
struct param_id : std::integral_constant< int, T::paramId > {}; 
template<template<class...>class Z, class T, class... Args> 
struct param_id<Z<T,Args...>> : param_id<T> {}; 

template<class T> 
constexpr int getId() { return param_id<T>::value; } 

constexpr是可選的,但在C++ 11意味着getId<SomeType>()是編譯時在許多情況下進行評估。

這意味着getId< std::vector< std::vector<SomeType> > >()getId<SomeType>()。這也意味着如果你想讓其他基元類型有一個固定的ID,你可以手動專家param_id

如果你想要一個工業強度的解決方案,我會盡可能地創建一個基於ADL的查找方案,但這是一個更復雜的答案。

std::integral_constant是另一個C++ 11ism。如果你缺乏這種支持,取代

template<class T> 
struct param_id : std::integral_constant< int, T::paramId > {}; 

template<class T> 
struct param_id { enum {value=T::paramId}; }; 
+0

謝謝你,對我很好! – yudjin 2014-09-02 06:13:53