C++11 将std::hash专门化到派生类

C++11 将std::hash专门化到派生类,c++11,gcc,hash,template-specialization,stdhash,C++11,Gcc,Hash,Template Specialization,Stdhash,我有一个抽象的基类Hashable,可以进行散列的类就是从这个基类派生出来的。现在我想将std::hash扩展到从Hashable派生的所有类 下面的代码应该就是这样做的 #include <functional> #include <type_traits> #include <iostream> class Hashable { public: virtual ~Hashable() {} virtual std::size_t Hash

我有一个抽象的基类
Hashable
,可以进行散列的类就是从这个基类派生出来的。现在我想将
std::hash
扩展到从
Hashable
派生的所有类

下面的代码应该就是这样做的

#include <functional>
#include <type_traits>
#include <iostream>

class Hashable {
public:
    virtual ~Hashable() {}
    virtual std::size_t Hash() const =0;
};

class Derived : public Hashable {
public:
    std::size_t Hash() const {
        return 0;
    }
};

// Specialization of std::hash to operate on Hashable or any class derived from
// Hashable.
namespace std {
template<class C>
struct hash {
  typename std::enable_if<std::is_base_of<Hashable, C>::value, std::size_t>::type
  operator()(const C& object) const {
    return object.Hash();
  }
};
}

int main(int, char**) {
    std::hash<Derived> hasher;
    Derived d;
    std::cout << hasher(d) << std::endl;

    return 0;
}
#包括
#包括
#包括
类散列{
公众:
虚拟~Hashable(){}
虚拟std::size\u t Hash()const=0;
};
派生类:公共哈希表{
公众:
std::size\u t Hash()常量{
返回0;
}
};
//对std::hash进行专门化,以便对Hashable或从其派生的任何类进行操作
//散列。
名称空间标准{
模板
结构散列{
typename std::enable_if::type
运算符()(常量C和对象)常量{
返回object.Hash();
}
};
}
int main(int,char**){
散列哈希器;
导出d;

std::cout似乎没有合适的方法来完成我想做的事情。我决定使用以下宏为每个派生类编写单独的专门化:

// macro to conveniently define specialization for a class derived from Hashable
#define DEFINE_STD_HASH_SPECIALIZATION(hashable)                               \
namespace std {                                                                \
template<>                                                                     \
struct hash<hashable> {                                                        \
  std::size_t operator()(const hashable& object) const {                       \
    return object.Hash();                                                      \
  }                                                                            \
};                                                                             \
}

呃,不,代码被破坏了。你不允许在
std
中声明新模板。你只能在某些条件下编写现有模板的专门化。你拥有的不是专门化即使我们忽略了关于你是什么的规则,也不允许你在std命名空间中做什么,你的类是一个重新定义n这在任何上下文中都是不允许的,即使它被允许,使用它也会有歧义,因为两个定义都会匹配。你必须为每种类型专门化,或者只为
Hashable
专门化,并且只为它的所有派生类型使用
std::hash
。这就是为什么我不喜欢模板这样的特性而不是函数通过adl。谢谢你的评论。我怀疑我的解决方案不太符合犹太教标准,事实上,我很惊讶它在gcc 4.8.1中完全有效。我决定为每个派生类编写单独的专门化。
// macro to conveniently define specialization for a class derived from Hashable
#define DEFINE_STD_HASH_SPECIALIZATION(hashable)                               \
namespace std {                                                                \
template<>                                                                     \
struct hash<hashable> {                                                        \
  std::size_t operator()(const hashable& object) const {                       \
    return object.Hash();                                                      \
  }                                                                            \
};                                                                             \
}
// specialization of std::hash for Derived
DEFINE_STD_HASH_SPECIALIZATION(Derived);