In my code I'd like to make unordered sets with only one template parameter (if possible) like so:
std::unordered_set<std::shared_ptr<Foo>> my_foos;
The problem is that my Foo
class also have a class member which is of the type std::unordered_set<std::shared_ptr<Foo>>
. Specifically my Foo
class looks something like this:
#include<unordered_set>
#include<memory>
class Foo {
explicit Foo(int val) : val_(val) {}
void AddFoo(Foo& foo){foos.insert(std::make_shared<Foo>(foo));}
std::unordered_set<std::shared_ptr<Foo>> foos;
int val_;
};
namespace std {
template <>
struct hash<shared_ptr<Foo>> {
size_t operator()(const Foo shared_ptr<Foo>& foo) const {
return hash<int>()(foo->val_);
}
};
template <>
struct equal_to<Foo> {
bool operator()(const Foo shared_ptr<Foo>& lhs, const Foo shared_ptr<Foo>& rhs) const {
return lhs->val_ == rhs->val_;
}
};
}
This gives the error
error: specialization of 'std::hash<std::shared_ptr<Foo> >' after instantiation
How can I resolve this issue?
I got your code to compile. Had to add forward declarations, separate definition from declaration (otherwise it couldn't find Foo
's members) for those structs, added public
access specifier in Foo
. Also, there was some code to cleanup in the function signatures.
#include <memory>
#include <unordered_set>
class Foo; // forward declaration of Foo here
namespace std {
template <>
struct hash<shared_ptr<Foo>> {
size_t operator()(const shared_ptr<Foo>& foo) const;
};
template <>
struct equal_to<Foo> {
bool operator()(const shared_ptr<Foo>& lhs,
const shared_ptr<Foo>& rhs) const;
};
} // namespace std
class Foo {
public:
explicit Foo(int val) : val_(val) {}
void AddFoo(Foo& foo) { foos.insert(std::make_shared<Foo>(foo)); }
std::unordered_set<std::shared_ptr<Foo>> foos;
int val_;
};
size_t std::hash<std::shared_ptr<Foo>>::operator()(
const std::shared_ptr<Foo>& foo) const {
return std::hash<int>()(foo->val_);
}
bool std::equal_to<Foo>::operator()(const std::shared_ptr<Foo>& lhs,
const std::shared_ptr<Foo>& rhs) const {
return lhs->val_ == rhs->val_;
}