I'm trying to implement an undirected graph:
template<typename NodeType, typename Edge>
class Graph {
public:
Graph() = default;
Graph& Add(const Edge &edge, const NodeType &from, const NodeType &to) {
auto node = graph.emplace(Node(from)); //passing ‘const std::set<Graph<City, Train>::Node, std::less<Graph<City, Train>::Node>, std::allocator<Graph<City, Train>::Node> >’ as ‘this’ argument discards qualifiers
(node.first)->edges.emplace_back(edge);
node = graph.emplace(Node(to));
(node.first)->edges.emplace_back(edge);
return *this;
}
void PrintGraph() const {
for(const auto &node : graph) {
cout << node.id << ":" << endl;
for(const auto &edge : node.edges)
cout << "-> " << edge << endl;
}
}
private:
class Node {
public:
Node(const NodeType &val): id(val) {}
Node(const Node &other): id(other.id) {
copy(other.edges.begin(), other.edges.end(), edges);
}
bool operator<(const Node &other) const {
return id < other.id;
}
NodeType id;
vector<Edge> edges;
};
set<Node> graph;
};
This won't compile due to my (node.first)->edges.emplace_back()
: error: passing ‘const std::vector<Train, std::allocator<Train> >’ as ‘this’ argument discards qualifiers [-fpermissive]
which I don't understand:
member function
Add()
returns a reference to itself since I want to chain it. It cannot be aconst reference
since the function modifies its class members.member function
Add()
cannot beconst
as it could add a Node or Node's edge.it's possible that
graph.emplace()
returnspair<set::const_iterator,bool>
so I try verifying it by changing topair<set<Node>::const_iterator,bool> node =
but then a whole new set of problems arises: type/value mismatch at argument 1. I thoughtset::emplace
return a pair of iterator to new/existing element and true/false depending on whether new element was added. Where am I wrong here?
So what's wrong with my Add()
?
I use my templated graph class on the following classes:
class City {
public:
City(const string &cityName): name(cityName) {}
City(const City &cpy) = default;
friend ostream& operator<<(ostream &os, const City &city) {
os << city.name;
return os;
}
bool operator<(const City &other) const {
return this->name < other.name;
}
bool operator==(const City &other) const {
return this->name == other.name;
}
string name;
};
class Train {
public:
Train(const string &trainName): name(trainName) {}
Train(const Train &cpy) = default;
friend ostream& operator<<(ostream &os, const Train &train) {
os << train.name;
return os;
}
bool operator<(const Train &other) {
return this->name < other.name;
}
bool operator==(const Train &other) const {
return this->name == other.name;
}
string name;
};
The class is used this way:
Graph<City,Train> network;
network.Add(Train("train 1"), City("city 1"), City("city 2")).Add(Train("train 2"), City("city 1"), City("city 2"));