我猜测std::hash
被定义为模板结构,以避免在重载函数解析期间完成隐式类型转换.这是正确的说法吗?
我的意思是,我更愿意写
std::string s;
size_t hash = std::hash(s);
Run Code Online (Sandbox Code Playgroud)
代替
std::string s;
size_t hash = std::hash<std::string>()(s);
Run Code Online (Sandbox Code Playgroud)
但我猜测标准委员会选择第二种选择的原因是有原因的.
编辑:修复第二个代码片段.
mil*_*bug 10
部分特化功能模板是不可能的,因此对于用户定义的模板化类,std::hash
如果它是一个函数,则无法专门化.(您只能从std
命名空间中专门化模板,但不能重载,因此模板化类的用户无法创建std::unordered_map<MyClass<whatever>, MyOtherClass>
,他们将被迫选择std::unordered_map<MyClass<whatever>, MyOtherClass, ???>
).这里的functor就是解决方案.
namespace std
{
template<typename T>
struct hash<MyVector<T>>
{
size_t operator()(const MyVector<T>& v)
{
//return hash from here
}
};
}
Run Code Online (Sandbox Code Playgroud)
标准库的替代方法是使用一些SFINAE模板技巧来选择成员.hash()
作为默认值,如果是另一种情况则使用标准哈希,但在大多数情况下,您无法改进接口(特别是如果使用第三方代码)
另一种选择就像std::swap
是(ADL的技巧):
//somewhere in std::unordered_map
using std::hash;
size_t h = hash(key);
Run Code Online (Sandbox Code Playgroud)
根据我的经验,ADL很棘手并不是每个人都记得角落案件.此外,这里的仿函数的优点是你可以将它们用作模板参数,所以std::unordered_map<A, B, specialized_hash<A>>
如果你认为默认情况适合你的情况,你可以插入另一个仿函数(如).
来自评论:
但是你能详细说明一下std :: swap吗?它仍然存在于C++ 11中,它对用户定义的类型没有任何问题,是吗?为什么在STL中保留了许多不同的概念而不是使它更加一致?
std::swap
和之间有一点区别std::hash
:
在std::hash
:
std::string
类作者定义的哈希对你的情况来说是不够的,也就是说,它太通用了,你可以在你的哈希映射中保证你只会输入一种字符串,所以你可以提供哈希功能更快或/和碰撞更少.在std::swap
:
std::swap
那个,而不是那个调用复制构造函数的泛型函数.std::vector
可以实现为动态数组,指针隐藏为私有字段,因此您将无法访问它们,不是单独交换它们,甚至不能保证以这种方式实现的事实)std::swap
:标准容器提供swap
成员函数,std::swap
可以是专用的(但仅适用于非模板化的类),而交换可以定义为ADL中的自由函数.你应该如何提供自己的交换?国际海事组织令人困惑,而不是std::swap
功能和std::hash
运气的事实.为什么STL不一致?我只能在这里猜测,但STL不一致的主要原因是(a)bawkward兼容性和(b)C++也非常不一致.