2014-09-01 54 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