Reputation: 9369
Consider the following code. I want to specialize std::hash<>
used in a Map
, according to the value of a static data member of the Array class. Note that Array depends on Map
itself.
// Array.h
#include <unordered_map>
using namespace std;
class Array;
typedef pair<int, int> Point;
namespace std {
template <> struct hash<Point> {
size_t operator()(const Point & p) const {
return p.second * Array::C + p.first; // error: incomplete type ‘Array’ used in nested name specifier
}
};
}
typedef unordered_map<Point, Array, hash<Point> > Map;
class Array {
public:
static const int R = 5, C = 5;
Map compute() {/*...*/}
};
Of course, in the above specialization Array
is not complete yet, so the compiler complains. However, if I move the specialization below the class definition, I obtain another error:
error: specialization of ‘std::hash<std::pair<int, int> >’ after instantiation
Upvotes: 3
Views: 291
Reputation: 361442
I think you pretty much know the reason why you're getting that error, so I wouldn't explain that. However, if you want to explore that part also, then I will definitely explain that.
As for how to solve this problem, alright, I would do three things:
First, I wouldn't specialize std::hash
to begin with!
Second, I would write my own MyHash
class template, which I would instantiate with Array
type, instead of Point
type. Also note that the parameter type to operator()
isn't Array
, rather it is Point
, as it should be.
Third, I would move the typedef
of Map
inside the class Array
.
Here is what I mean:
template <typename A>
struct MyHash
{
size_t operator()(const Point & p) const
{
return p.second * A::C + p.first;
}
};
class Array {
public:
typedef unordered_map<Point, Array, MyHash<Array> > Map;
static const int R = 5, C = 5;
Map compute() {/*...*/}
};
Online demo : http://ideone.com/hwLIT
Upvotes: 0
Reputation: 7985
You are using the static member before the class is defined. Fix this by moving the implementation of hash
after Array
:
// Array.h
#include <unordered_map>
using namespace std;
class Array;
typedef pair<int, int> Point;
namespace std {
template <> struct hash<Point>;
}
typedef unordered_map<Point, Array, hash<Point> > Map;
class Array {
public:
static const int R = 5, C = 5;
Map compute();
};
namespace std {
template <> struct hash<Point> {
size_t operator()(const Point & p) const {
return p.second * Array::C + p.first;
}
};
}
Upvotes: 1