我有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 >()
一样调用 - 它会不一致。
答案 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}; };