Paresh
Paresh

Reputation: 552

Comparator for set defined in the class of the set elements

I have a class, and the pointers to the objects of this class need to be placed in a std::set. I want to define the comparator inside the class. I have seen a few solutions where either a separate class is defined (I guess it is called a functor), or a structure is defined which overloads the operator(). I want to avoid this boilerplate code, and want to define a comparator as a member of the class itself, something along the lines of Java's compareTo() method.

Let us say, my class is something like:

class Item {
private:
    int id;
    float score;
.....
public:
// Rest of the methods and setters/getters
}

I want to define the comparator in a way that pointer to object having a higher score are placed first in the set. If the score is equal for the two, then the one with the lower id is placed first. I guess the code will be something like the following, but since I did not understand this part very well, please correct me (I would like this to be placed inside the class itself):

bool operator()(const Item* a, const Item* b) {
    if (a->score != b->score) return a->score > b->score;
    return a->id < b->id;
}

The usage would be as follows:

std::set<Item*> sortedItems;
Item* item = new Item();
sortedItems.insert(item);

I am not sure if the comparator needs to be specified at all in the std::set template if defined within the class, and if so, how? Also, how do I add this comparator in the class itself? I am new to STL, and fairly new to C++ as well. Thanks!

Upvotes: 2

Views: 3286

Answers (2)

andre
andre

Reputation: 7249

this solution is inspired by this answer.

#include <set>

class Item {
private:
    int id;
    float score;
public:
    struct compare {
        bool operator()(const Item* a, const Item* b) {
             if (a->score != b->score) return a->score > b->score;
             return a->id < b->id;
        }
    };
};

Because set allows you to define your own comparison method you can use it as follows.

std::set<Item*, Item::compare> sortedItems;

This should allow your class Item to work with set

Upvotes: 5

Pete Becker
Pete Becker

Reputation: 76245

The set<T> implementation wants to call a < b where a and b are objects of type T. As long as that call is valid, the set doesn't care; it can be a non-static member function that takes one argument, a static member function that takes two arguments, or a free function that takes two argument:

class Item {
public:
    bool operator<(const Item& rhs) {
        return score == rhs.score ? id < rhs.id : score < rhs.score;
    }
static bool operator<(const Iterm& lhs, const Item& rhs) {
    return lhs.score == rhs.score ? lhs.id < rhs.id : lhs.score < rhs.score;
}
};

bool operator<(const Item& lhs, const Item& rhs) {
    return lhs.score == rhs.score ? lhs.id < rhs.id : lhs.score < rhs.score;
}

Any one of those three is okay. Of course, if you write two or more of them, you'll get ambiguities.

Upvotes: 2

Related Questions