将模板参数区分为嵌套模板

时间:2014-09-01 19:27:44

标签: c++ templates

我有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 > >()会调用三维变体?或者我可以区分嵌套模板的编译时模板魔法?

因为在整个代码中使用了Some< NestedType >之类的符号,并且我不想更改它并像getId< SomeType, NestedType >()一样调用 - 它会不一致。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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}; };