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



考虑

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 命名空间中,但第一个不会导致任何编译器警告?

这与核心语言问题727有关(决议后删除文本,决议后新增斜体文本,粗体文本由我强调(:

应在包含专用模板的命名空间中声明显式专用化。声明符 ID 或类头名称不限定的显式专用化应在模板最近的封闭命名空间中声明,或者,如果命名空间是内联的 (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 都接受该代码(请注意,旧版本的 Clang 拒绝了它(。对于 GCC,这已经是一个报告的错误。

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

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

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

最新更新