用户类型的hash <T>仿函数属于哪个命名空间?

Hug*_*ues 11 c++ hash namespaces c++11

我不清楚C++ 11标准中hash<T>应该定义用户定义的仿函数.

例如,在23.5.2 Header中<unordered_map>,它显示:

template <class Key,
        class T,
        class Hash = hash<Key>,
        class Pred = std::equal_to<Key>,
        class Alloc = std::allocator<std::pair<const Key, T> > >
    class unordered_map;
Run Code Online (Sandbox Code Playgroud)

这表明,默认情况下,hash<T>在全局命名空间equal_to<>中搜索,而在std命名空间中搜索.

为什么名称空间hash<>equal_to<>?之间存在差异?

(实际上,在http://www.cplusplus.com/reference/unordered_map/unordered_map/的描述中,都没有指定std命名空间.)

因此,在hash<>为用户类型定义仿函数时,是应该将它包含在namespace std { }块中,还是可以保留在当前命名空间中?

如果代码没有using namespace std;,那么STL容器如何unordered_map知道在std命名空间中查找hash<>与基元类型相关联的预定义仿函数?看起来默认Hash = hash<Key>会找不到这些.

对不起,如果这些都是愚蠢的问题..

ybu*_*ill 6

首先,模板没有"参数依赖查找".因此hash<Key>,无论是std在全局命名空间中还是在全局命名空间中,都将始终引用相同的模板Key.如果它已解析为不同翻译单元中的不同模板,则会因ODR违规而导致未定义的行为.仅这一点就表明,hash在这里是指std::hash,这是因为,如果unordered_map被宣布是这样的:

namespace std {
    template<class T> struct hash;

    template <class Key,
        class T,
        class Hash = hash<Key>,    // resolves to std::hash<Key> for all Keys
        class Pred = std::equal_to<Key>,
        class Alloc = std::allocator<std::pair<const Key, T> > >
    class unordered_map;
}
Run Code Online (Sandbox Code Playgroud)

但是,标准头中声明的类型不需要在源代码中编写(它们原则上可以内置于编译器中,也可以通过其他魔法预编译).该标准要求每个标准头仅在其概要中声明类型,这意味着通过省略std::hash声明,该标准允许一些假设的实现以避免上述命名空间污染.这解释了为什么在概要中没有看到上述声明.

为了进一步补充上述结论,我们转到§20.8.12类模板hash [unord.hash],其内容如下:

23.5中定义的无序关联容器使用类模板哈希的特化作为默认哈希函数.

本段指的是std::hash我们可以从概要中推断出来的<functional>.

底线:这是标准格式的不一致.存在许多不一致之处,因此这个具体案例并不令人惊讶.在这种情况下,人们必须通过推断出唯一合情合理的东西来理解其意图.

专业化.您在声明它们的命名空间中专门化模板.您被明确授予专门为您自己的类型标准模板的权利:

namespace std {
    template<> struct hash<YourClass> {
        // specialization goes here
    };
}
Run Code Online (Sandbox Code Playgroud)