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

时间:2018-05-07 04:02:57

标签: c++ template-specialization 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;
    }
};

在这种情况下,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;
    }
};

导致我们预期的错误。

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

2 个答案:

答案 0 :(得分:3)

这与Core Language Issue 727有关(删除文本在解析后删除,斜体文本在解析后新添加,粗体文本由我强调):

  

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

请注意粗体文本,std::hash最近的封闭命名空间为std,并且您的显式特化未在std中声明,因此在解析之前它是错误的。部分特化没有这个约束,所以你的第一个例子在解决之前就已经很好了。

现在,您的示例在解决后应该是格式良好的。您可以看到Clang和MSVC accept the code(请注意旧版本的Clang rejects it)。对于GCC,这已经是reported bug

答案 1 :(得分:0)

正如这里所写http://umich.edu/~eecs381/handouts/NamespaceGuide.pdf

  

“您指示编译器在全局命名空间的std命名空间中创建所有名称,因此它们可以是   在您的源代码文件的其余部分中没有限定地引用。它们现在将与您自己的代码使用的任何名称冲突。   这仅对当前编译单元(正在编译的文件)有效。“

第一个是很好的示例,因为您将所有std内容(如hash模板)导入到全局命名空间,因此您可以编写其专业化而不会出错。在第二种情况下,它不起作用,因为任何hash模板的泄漏都是专门的。