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

mik*_*ike 5 c++

为什么要向前宣布如下:

template<typename T> struct std::hash;
Run Code Online (Sandbox Code Playgroud)

无法使用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;
                                  ^~~~
Run Code Online (Sandbox Code Playgroud)

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;
                            ^~~~~
Run Code Online (Sandbox Code Playgroud)

它在VS(http://webcompiler.cloudapp.net/)下工作.哪个编译器是对的?

顺便说一句.C++ Primer第5版中使用了相同的声明.好吧 - 几乎一样,它使用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";
}
Run Code Online (Sandbox Code Playgroud)

The*_*Kid 1

原因似乎主要是因为前向声明的功能必须与常规声明非常相似。即封装在名称空间中,不以 1 为前缀。我想这将允许使用相同的解析器进行声明和前向声明,这是有意义的。