我想定义一个适用于给定基类的所有子类的C ++模板特化。这可能吗?
特别是,我想为STL的哈希<>执行此操作。散列<>被定义为一个空的参数化模板,以及一系列特定类型的特化:
template<class _Key>
struct hash { };
template<>
struct hash<char>
{
size_t
operator()(char __x) const
{ return __x; }
};
template<>
struct hash<int>
{
size_t
operator()(int __x) const
{ return __x; }
};
...
我想定义这样的内容:
template<class Base>
struct hash {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
class Sub : public Base {
public:
size_t my_hash() const { ... }
};
并能够像这样使用它:
hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);
但是,我的哈希模板与STL中的通用模板冲突。是否有一种方法(可能使用特征)来定义适用于给定基类的所有子类的模板特化(不修改STL定义)?
请注意,我知道只要需要这个哈希特化,我就可以使用一些额外的模板参数来执行此操作,但是如果可能的话我想避免这种情况:
template<>
struct hash<Base> {
size_t operator()(const Base& b) const {
return b.my_hash();
}
};
....
// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
答案 0 :(得分:1)
解决方案是使用SFINAE来决定是否允许根据类继承结构进行专业化。在Boost中,您可以使用enable_if
和is_base_of
来实现此目的。
答案 1 :(得分:0)
这是我能做的最好的事情:
template<>
struct hash<Sub> : hash<Base> {
};
我有点担心我不需要虚拟operator()
。
答案 2 :(得分:0)
自 C ++ 11 起,您可以将SFINAE与标准库enable_if和is_base_of一起使用来解决问题。
答案 3 :(得分:0)
我认为这是不可能的,因为基于比仅匹配类型更复杂的东西进行模板特化的方法是 C++ SFINAE,它需要第二个(虚拟)模板参数。不幸的是,std::hash
只接受一个模板参数,并且不允许使用两个模板参数创建另一个版本的 std::hash
。因此,如果您对 Jayen's solution 不满意,您可以创建自己的 hash
类型:
#include <iostream>
#include <type_traits>
using namespace std;
class ParentClass {};
class ChildClass : public ParentClass {};
// SFINAE, if T is not a child of ParentClass, substitution will fail
// You can create specializations for the general case, for another base classes, etc.
template<typename T, typename=typename enable_if<is_base_of<ParentClass, T>::value, T>::type>
struct your_hash
{
size_t operator()(const T& value)
{
return 42;
}
};
int main()
{
ParentClass pc;
ChildClass cc;
cout<<your_hash<ParentClass>()(pc)<<"\n";
cout<<your_hash<ChildClass>()(cc)<<"\n";
}