C++ 只要我能为我的类型提供哈希函数,为什么我需要为我的类型专门化std::hash?
只要我能为我的类类型提供我的C++ 只要我能为我的类型提供哈希函数,为什么我需要为我的类型专门化std::hash?,c++,template-specialization,C++,Template Specialization,只要我能为我的类类型提供我的hasher,我为什么要专门化std::hash 我已经实现了这个示例: class Foo; template<> class std::hash<Foo>; class Foo { public: Foo(std::string const& s, int x) : str_(s), x_(x){} std::string str()const {return str_;} int get_x() cons
hasher
,我为什么要专门化std::hash
我已经实现了这个示例:
class Foo;
template<>
class std::hash<Foo>;
class Foo
{
public:
Foo(std::string const& s, int x) : str_(s), x_(x){}
std::string str()const {return str_;}
int get_x() const{ return x_;}
private:
std::string str_;
int x_{};
friend bool operator==(Foo const&, Foo const&);
friend class std::hash<Foo>;
};
bool operator==(Foo const& lhs, Foo const& rhs)
{
return lhs.str_ == rhs.str_ && lhs.x_ == rhs.x_;
}
size_t hasher(Foo const& f)
{
return std::hash<std::string>()(f.str()) ^
std::hash<int>()(f.get_x());
}
namespace std
{
template <>
class hash<Foo>
{
public:
using argument_type = Foo;
using result_type = std::size_t;
result_type operator()(argument_type const& a)const;
};
typename hash<Foo>::result_type
hash<Foo>::operator()(argument_type const& a)const
{
return hash<std::string>()(a.str_) ^
hash<int>()(a.x_);
}
}
int main()
{
std::unordered_set<Foo, decltype(hasher)*> u(5, hasher); // needs hasher as template argument and as function argument
u.insert(Foo{"hi", 100});
std::unordered_set<Foo> u2; // doesn't need either
u2.insert(Foo("hi", 100));
std::cout << "\ndone!\n";
}
Foo类;
模板
类std::hash;
福班
{
公众:
Foo(std::stringconst&s,intx):str_us,x_x{}
std::string str()常量{return str_;}
int get_x()常量{return x_;}
私人:
std::string str;
int x{};
友元布尔运算符==(Foo const&,Foo const&);
friend类std::hash;
};
布尔运算符==(Foo const&lhs、Foo const&rhs)
{
返回lhs.str==rhs.str&&lhs.x_==rhs.x;
}
大小散列器(Foo const&f)
{
返回std::hash()(f.str())^
std::hash()(f.get_x());
}
名称空间标准
{
模板
类散列
{
公众:
使用参数_type=Foo;
使用结果\u type=std::size\u t;
结果类型运算符()(参数类型常量&a)常量;
};
typename散列::结果类型
hash::operator()(参数类型常量&a)常量
{
返回hash()(a.str_389;)^
hash();
}
}
int main()
{
无序_集u(5,散列);//需要散列作为模板参数和函数参数
u、 插入(Foo{“hi”,100});
std::无序_集u2;//两者都不需要
u2.插入(Foo(“hi”,100));
标准::cout
只要我能为我的类类型提供hasher,为什么我[需要]专门化std::hash
您不需要这样做。下面是一些这样做的原因:
- 如果您的
类
是API的一部分(内部或外部无关紧要),并且您希望为类的用户提供将其用作无序容器中的密钥的可能性(或出于任何其他原因,对其进行哈希),友好的方法是专门化std::hash
。没有人希望必须指定一个特殊函数来对(可能记录为)可散列的类型进行散列
- 因为它的代码并不比编写实际的散列算法(只是一个小样板)多多少,所以如果你打算不止一次或两次地使用它,你也可以为了自己的利益而这样做。这样可以使代码更干净
一旦编写了专门化,您就不需要自由散列函数,因此如果上述任何一项适用,您可以立即专门化std::hash
(并完全跳过自由散列函数)
使样板文件稍微短一点的一种方法是使用struct
而不是class
对其进行专门化
namespace std {
template<class Key>
struct hash;
}
名称空间std{
模板
结构散列;
}
所以这样做也很有意义。你的定义是:
namespace std {
struct hash<Foo> {
using argument_type = Foo;
using result_type = std::size_t;
result_type operator()(argument_type const& a) const;
};
}
名称空间std{
结构散列{
使用参数_type=Foo;
使用结果\u type=std::size\u t;
结果类型运算符()(参数类型常量&a)常量;
};
}
这是为了灵活性吗
提供专门化不会影响灵活性,但会使其更易于使用。您证明了您不需要专门化std::hash
,那么您想问什么?为什么它也是一个选项?