user1697083
user1697083

Reputation:

Using user defined types (structs) with container classes like set

I'm very new to C++ and I'm trying to use a user-defined type, a struct, with a container class, which in this case is a Set.

I know that to store elements of user-defined type, which can't be compared using the built-in relational operators, I'll need to write a comparison callback function and pass it to the Set constructor. I can't figure out what the syntax for this is, though.

I have this defined in my .cpp file:

Set<struct> included;

And then this is defined in a header file:

struct pointT { 
int row; 
int col; 

bool operator==(PointT p1, PointT, p2) {
    return p1.x == p2.x && p1.y == p2.y;

}

};

Is this all I need to do, or am I missing some big here, as the code doesn't seem to compile as the type is not recognized?

I've looked on this site for similar answers, but I can't find anything specific and clear to this situation. Any help would be appreciated.

Upvotes: 1

Views: 870

Answers (2)

Matthieu Poullet
Matthieu Poullet

Reputation: 427

You can try something like this:

#include <iostream>
#include <set>

namespace point {
    struct PointT {
        int x;
        int y;
    };

    bool operator==(const PointT& p1, const PointT& p2) {
        return p1.x < p2.x  ||  (p1.x == p2.x  &&  p1.y < p2.y);
    }

    bool operator<(const PointT& p1, const PointT& p2) {
        return p1.x < p2.x  &&  p1.y < p2.y;
    }

    bool operator<=(const PointT& p1, const PointT& p2) {
        return p1 < p2  ||  p1 == p2;
    }

    bool operator>(const PointT& p1, const PointT& p2) {
        return p2 < p1;
    }

    bool operator>=(const PointT& p1, const PointT& p2) {
        return p2 < p1  ||  p1 == p2;
    }
}


int main()
{
    using namespace point;
    std::set<PointT> s{ { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 1, 2 } };
    for (const auto& e : s) std::cout << "(" << e.x << "," << e.y << ")" << std::endl;
    return 0;
}

Upvotes: 0

Mike Seymour
Mike Seymour

Reputation: 254431

First, choose a name for the class; you're calling it variously pointT, PointT, and struct (which isn't even a valid name). I'll just call it point, since I don't like weird decorations on names.

Then you need to decide on the member names: are they row and col or x and y? I'll choose the first.

To store it in std::set (or, in general, to use it as a key in standard associative containers), you need operator<, not operator==, since associative keys are ordered. This can either be a member function with one parameter (this being the left-hand operand, and the parameter being the right-hand):

struct point {
    int row;
    int col;

    bool operator<(point const & rhs) {
        return std::tie(row, col) < std::tie(rhs.row, rhs.col);
    }
};

or a non-member with two parameters:

bool operator<(point const & lhs, point const & rhs) {
    return std::tie(lhs.row, lhs.col) < std::tie(rhs.row, rhs.col);
}

Note that my example implementation needs the C++11 <tuple> header, and assumes you want a lexicographical ordering (or don't particularly care about the ordering). If you're stuck in the past, then you'll need to write it yourself; something like:

bool operator<(point const & lhs, point const & rhs) {
    if (lhs.row < rhs.row) return true;
    if (rhs.row < lhs.row) return false;
    return lhs.col < rhs.col;
}

If your Set doesn't behave like a standard associative container, then it may have other requirements; but I can't guess what they might be. You'll have to consult that class's documentation.

Upvotes: 2

Related Questions