I simplified my question to this. Can I create a class that has an unordered set with template type itself? To be specific, for example a Square that has a pointer to an unordered set of neighbors. I got stuck trying to integrate a hash function with the class itself. Here is my code:
#include <iostream>
#include <unordered_set>
#define SIZE 200
#define MASTER 0
class Square;
namespace std{
template<>
struct hash<Square> {
std::size_t operator () (Square const &v) const
{
return v.r;
}
};
}
class Square{
public:
int c1, c2;
int r;
std::unordered_set<Square> *neigh;
Square() {
neigh = new std::unordered_set<Square>();
}
~Square(){
delete neigh;
}
bool operator==(const Square& second) {
return this->r == second.r
&& this->c1 ==second.c1
&& this->c2 == second.c2;
}
};
int main(int argc, char *argv[]) {
Square sq;
Square tt;
sq.neigh->insert(tt);
}
I tried to compile using g++ and FLAGS = --std=c++17 -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -ggdb. The error received was gigantic, starting with:
test.cpp: In member function ‘std::size_t std::hash<Square>::operator()(const Square&) const’:
test.cpp:15:20: error: invalid use of incomplete type ‘const class Square’
15 | return v.x;
I don't know what is the correct approach to this situation. Please take into consideration this is my simplified code version of what I need, so I really need a neighbors field.
To solve the problem you're asking about, just declare std::hash<Square>::operator()
before the Square
definition, but don't implement it:
namespace std{
template<>
struct hash<Square> {
std::size_t operator() (Square const &) const;
};
}
Then after the Square
definition, define the std::hash<Square>::operator()
:
namespace std {
std::size_t hash<Square>::operator() (Square const& v) const
{
// return calculation
}
}
You have a problem with the insert
too. You copy an object with a pointer and then destroy the same pointer twice. To remedy that, use a std::unique_ptr<std::unordered_set<Square>>
which helps since you'll get a compilation error if you try copying it.
class Square{
public:
std::unique_ptr<std::unordered_set<Square>> neigh;
Square() : neigh{std::make_unique<std::unordered_set<Square>>()} {}
// no destructor needed
bool operator==(const Square& second) const { // should be const
// ...
}
};
You then have to move
objects into place:
sq.neigh->insert(std::move(tt));
or emplace
them:
sq.neigh->emplace(...constructor arguments...);