1

I'm trying to create a graph, and I'm trying to do this by creating a set of type Vertex and set of type Edge. However, I'm getting this error:

Invalid operands to binary expression ('const Vertex' and 'const Vertex')

Is it even possible to hold objects in sets? I'm not a great coder, this is for my college project. If you see ** surrounding blocks of code, it's because I tried to make those portions bold to try and highlight, but it didn't work. Those ** 's are not in my actual code.

class Vertex
{
public:
    Vertex();
    Vertex(std::string);

    std::string getVertexName();
private:
    std::string name;
};
class Edge{
    Edge();
    Edge(std::string, std::string);

    std::string source;
    std::string destination;
};
class Graph{
public:
    void buildGraph( );
    void createVertex(std::string vertexName);

    // **
    std::set <Vertex> setofvertices;
    std::set <Vertex>::iterator itervertex = setofvertices.begin();
    std::set <Edge> setofedges;
    std::set <Edge>::iterator iteredge = setofedges.begin();
    // **
};

Graph* DataSource:: buildGraph()
{
    Graph *createdGraph;
    //Vertex *createdVertex;
    std::ifstream inputFile;
    std::string followee, follower;
    inputFile.open(this->filename);
    if (inputFile.is_open()){
        std::stringstream line;
        std::string fileLine;

        createdGraph = new Graph();
        while(true){
            getline(inputFile, fileLine);
            if (inputFile.eof()) break;
            line.clear();
            line.str(fileLine);
            line >> followee >> follower;
            std::cout << followee << "   " << follower << std::endl;

            // **
            createdGraph->setofvertices.insert(followee);
            createdGraph->setofvertices.insert(follower);
            createdGraph->setofedges.insert(followee,follower);
            // **
        }
    return createdGraph;
}
273K
  • 19,191
  • 8
  • 34
  • 47

1 Answers1

0

The error is because items in a set are sorted and Vertex and Edge don't provide a mechanism for that. The easiest way to do that is to implement operator< in both.

Here's a simple example of how that might look. I made the members public to make it easier to print at the end but you can keep them private.

#include <iostream>
#include <set>
#include <string>
#include <tuple>

class Vertex
{
public:
    Vertex(std::string name_) 
        : name(name_)
    {}

    bool operator<(const Vertex &rhs) const
    {
        return name < rhs.name;
    }

    std::string name;
};

class Edge
{
public:
    Edge(std::string source_, std::string destination_)
        : source(source_), destination(destination_)
    {}

    bool operator<(const Edge &rhs) const
    {
        // Easy way to handle comparison of multiple variables
        // https://en.cppreference.com/w/cpp/utility/tuple/tie
        return std::tie(source, destination) < std::tie(rhs.source, rhs.destination);
    }

    std::string source;
    std::string destination;
};

class Graph
{
public:
    std::set <Vertex> setofvertices;
    std::set <Edge> setofedges;
};

int main()
{
    Graph g;
    g.setofvertices.emplace(Vertex("a"));
    g.setofvertices.emplace(Vertex("b"));
    g.setofvertices.emplace(Vertex("c"));
    // intentional duplicate that will be rejected
    g.setofvertices.emplace(Vertex("c"));

    g.setofedges.emplace(Edge("a", "b"));
    // intentional duplicate that will be rejected
    g.setofedges.emplace(Edge("a", "b"));
    g.setofedges.emplace(Edge("b", "c"));
    g.setofedges.emplace(Edge("c", "a"));

    for (auto &v : g.setofvertices)
    {
        std::cout << "Vertex: " << v.name << "\n";
    }
    for (auto &e : g.setofedges)
    {
        std::cout << "Edge : " << e.source << " -> " << e.destination << "\n";
    }
}

You might consider replacing this code:

while(true){
    getline(inputFile, fileLine);
    if (inputFile.eof()) break;

with just while (getline(inputFile, fileLine)) { ... }. It's equivalent to what you have now but clearer and will catch any other error that might occur while reading that isn't eof.

It's a common trap for folks to fall into where they check for eof before reading, the read fails, and then they process using bad data but the way you've done it, with the check after the read, eliminates that loophole.

Retired Ninja
  • 4,620
  • 3
  • 23
  • 35
  • 1
    Wow this is great, thank you so much, I really appreciate the help. I also didn't know about the eof, I'll make sure to make that change. – Sheehab Zaman May 03 '20 at 21:03