std::hash模板特化的前向声明

5
为什么要按如下方式进行前向声明:
template<typename T> struct std::hash;

使用gcc和clang编译失败,但可以通过Visual Studio 2015编译?

gcc 6.1.0(使用coliru):

main.cpp:11:34: error: invalid use of template-name 'std::hash' without an argument list
 template<typename T> struct std::hash;
                                  ^~~~

clang 3.8.0(使用coliru):


main.cpp:11:29: error: forward declaration of struct cannot have a nested name specifier
template<typename T> struct std::hash;
                            ^~~~~

这段代码在VS (http://webcompiler.cloudapp.net/)下运行。哪个编译器是正确的呢?

顺便提一下,《C++ Primer 第五版》中也使用了相同的声明。不过,在该书中使用了 class 代替 struct,这是错误的:template <class T> class std::hash;

完整代码:

#include <unordered_map>

/*
// compiles with gcc,clang,VS
namespace std {
  template<typename T>
  struct hash;
}*/

// Compiles only with VS
template<typename T> struct std::hash;

struct MyData {
  MyData() {}
  MyData(int d1, int d2) : data1(d1), data2(d2) {}
  bool operator==(const MyData& rop) const {
    return rop.data1 == data1 && rop.data2 == data2;
  }

  friend struct std::hash<MyData>;
 private:
  int data1;
  int data2;
};

namespace std {
  template<>
  struct hash<MyData> {
    typedef MyData argument_type;
    typedef size_t result_type;
    size_t operator()(const argument_type& data) const noexcept;
  };

  size_t hash<MyData>::operator()(const argument_type& data) const noexcept {
    return hash<unsigned>()(data.data1) ^ hash<unsigned>()(data.data2);
  }
}

int main() {
  std::unordered_map<MyData, std::string> mm;
  mm[MyData(1,1)] = "test1";
  mm[MyData(2,2)] = "test1";
}

4
如果代码在GCC或Clang下无法编译,但在MSVC下可以编译,那么通常是因为MSVC的问题。 - jonspaceharper
MSVC 以在解析符合标准的代码方面存在固有缺陷而闻名。 - πάντα ῥεῖ
@alain 你可以在那里放置专业化。 - mike
有趣的是,使用gcc/clang编译template<typename T> struct hash;可以通过,但在VS中失败了。这就像gcc/clang不需要命名空间限定一样? - mike
1
全局命名空间与 std 命名空间是不同的。因此,template <typename T> struct hash; 是合法的,但它是 hash 而不是 std::hash 的前向声明。除了特化之外,扩展 std 命名空间是被禁止的,但前向声明并不是一种扩展。 - 1stCLord
显示剩余2条评论
1个回答

1
似乎主要原因是前向声明必须像常规声明一样运作,即被包含在命名空间中,而不是带有前缀。我猜这将允许使用相同的解析器用于声明和前向声明,这是有意义的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接