在这种特殊情况下,为什么不需要将std :: hash()的特化注入到std命名空间中?

111*_*001 5 c++ specialization template-specialization

考虑

using namespace std;

template <typename S, typename T> struct hash<pair<S, T>>
{
    inline size_t operator()(const pair<S, T> &v) const
    {
        return 0;
    }
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,GCC和Clang都可以编译好,没有任何警告.然而,这似乎与我在线阅读的内容相矛盾,即定义您自己的哈希函数与标准库的无序类型一起使用需要您将定义放在std命名空间中.

有趣的是,专门针对pair<int, int>:

template <> struct hash<pair<int, int>>
{
    size_t operator()(const pair<int, int> &v) const
    {
        size_t seed = 0;
        return seed;
    }
};
Run Code Online (Sandbox Code Playgroud)

导致我们预期的错误.

但是,为什么第一个不会导致任何编译器警告,尽管我们没有将它放在std命名空间中?

xsk*_*xzr 3

这个与核心语言Issue 727有关(删除的文字是解决后删除的,斜体文字是解决后新添加的,粗体文字是我强调的):

明确的专业化应在包含专用模板的命名空间中声明。其 declarator-id 或 class-head-name 未限定的显式特化应在 template 的最近的封闭命名空间中声明,或者,如果命名空间是内联的 (10.3.1 [namespace.def]),则应在其内的任何命名空间中声明。封闭的命名空间集。这样的声明也可以是定义 可以在定义相应主模板的任何范围内声明(10.3.1.2 [namespace.memdef]、12.2 [class.mem]、17.6.2 [temp.mem])。

请注意粗体文本,最近的封闭命名空间 is std::hash,std并且您的显式专业化未在 中声明std,因此在解析之前它的格式不正确。部分专业化没有这个限制,因此您的第一个示例甚至在解析之前就已经是格式良好的。

现在,您的两个示例在解析后都应该格式良好。您可以看到 Clang 和 MSVC 都接受该代码(请注意旧版本的 Clang拒绝它)。对于 GCC,这已经是一个已报告的错误。