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
  • 29,503
  • 10
  • 41
  • 64
  • `I'm getting this error: ` Please post the exact full error message. – KamilCuk May 03 '20 at 17:43
  • 3
    Objects placed in sets need to be sorted. You need to provide an `operator<` that implements strict weak ordering. – Retired Ninja May 03 '20 at 17:46
  • Yes it's possible to store objects in a set. But you aren't doing it right. Read a book is probably the best advice I can give. – john May 03 '20 at 17:48
  • @KamilCuk sorry, I attached a screenshot at the bottom if that helps. – Sheehab Zaman May 03 '20 at 17:49
  • The screen shot indicates that the error is as Retired Ninja said. – john May 03 '20 at 17:49
  • @RetiredNinja Hi, thanks for the reply, I saw your replies on another post about a similar issue, and I was trying to implement operators, but I wasn't exactly sure how to implement that for my code where strings are being compared. – Sheehab Zaman May 03 '20 at 17:50
  • @SheehabZaman You can compare strings with `<`. – HolyBlackCat May 03 '20 at 17:56
  • I think I kind of understand what to do now. Thanks for the help everyone, it's my first time on stack overflow, and didn't expect so much help so quickly – Sheehab Zaman May 03 '20 at 18:03

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,785
  • 3
  • 25
  • 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