I have the following Graph class:
class Graph {
private:
struct Edge {
string vertex1{}, vertex2{};
int val{};
Edge() = default;
~Edge() = default;
explicit Edge(string v1, string v2, int value) : vertex1(std::move(v1)), vertex2(std::move(v2)), val(value) {};
bool operator==(const Edge&) const;
};
unordered_map<Edge, Edge*> edges;
public:
Graph() = default;
~Graph();
}
When I want to construct a Graph with the default constructor, it says Explicitly defaulted default constructor of 'Graph' is implicitly deleted because field 'edges' has a deleted default constructor
. How should I change my code, to be able to use the default constructor of Graph?
The Key in an unordered_map
needs to be hashable. Either by adding a specialization of the std::hash
class template or by providing a hashing functor when creating the unordered_map
.
You haven't shown that you've made a std::hash<Edge>
specialization and you aren't creating the unordered_map
with a functor to do the hashing which is why default construction fails.
To add a std::hash<Edge>
specialization you could do this (if you make Edge
public):
namespace std {
template<>
struct hash<Graph::Edge> {
size_t operator()(const Graph::Edge& e) const {
size_t hash_result;
// calculate the hash result
return hash_result;
}
};
} // namespace std
If you'd like to keep Edge
private
it may be easier to use a functor. Here's an example in the form of a struct
which makes the unordered_map
default constructible:
class Graph {
private:
struct Edge {
// ...
};
// the hashing functor:
struct edge_hasher {
size_t operator()(const Edge& e) const {
// an example implementation using boost::hash_combine
// from <boost/container_hash/hash.hpp>:
std::hash<std::string> h;
size_t hash_result = 0;
boost::hash_combine(hash_result, h(e.vertex1));
boost::hash_combine(hash_result, h(e.vertex2));
boost::hash_combine(hash_result, std::hash<int>{}(e.val));
return hash_result;
}
};
std::unordered_map<Edge, Edge*, edge_hasher> edges; // <- hasher included
public:
Graph() = default;
~Graph();
}