Why forward declaration as follows :
template<typename T> struct std::hash;
fails to compile with gcc and clang, but compiles with Visual Studio 2015?
gcc 6.1.0 (using 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 (using coliru):
main.cpp:11:29: error: forward declaration of struct cannot have a nested name specifier
template<typename T> struct std::hash;
^~~~~
it works under VS (http://webcompiler.cloudapp.net/). Which compiler is right?
btw. the same declaration is used in C++ Primer 5th edition. Well - nearly the same it uses class
instead of struct
: template <class T> class std::hash;
which is wrong.
full code:
#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";
}
The reason, seems to be largely because a forward declaration has to function much like a regular declaration. i.e. encased in a namespace, not prefixed by one. I guess this would allow the same parser to be used for declarations and forward declarations which makes sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With