为什么std :: hash不是重载函数?

Ale*_*lik 7 c++11 stdhash

我猜测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++也非常不一致.

  • 对不起,请再试一次:此提案讨论了如何避免为哈希专业化打开std命名空间以及如何使用ADL:[link](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012 /n3333.html) (2认同)