将模板参数作为嵌套模板区分开来

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 > >()精确调用第三个变体?或者说,我可以使用哪种编译时模板魔法来区分嵌套的模板?
因为在整个代码中,像Some< NestedType >这样的符号被用到了,而我不想更改它,并像getId< SomeType, NestedType >()一样调用 - 这将是不一致的。
2个回答

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


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++11语法。如果您缺少该支持,请进行替换。

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

使用

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接