Search code examples
c++setcontainerspriority-queue

std::set different comparer for inserting and ordering


I need a structure in which I can insert elements, have no duplicate, use a custom comparer and have the smallest element first. I tried using std::priority_queue, but the problem is that I get a lot of duplicates and I run out of space. So I thought about using std::set :
std::set< std::pair<Coordinates, int>, Compare> positions; where

Coordinates
{
public:
    Coordinates(int x = 0, int y = 0, char tool = 'T') : x(x), y(y), tool(tool) {}

public:
    int x, y;
    char tool;
};
class Compare
{
public:
    bool operator() (const std::pair<Coordinates, int>& c1, const std::pair<Coordinates, int>& c2) const
    {
        return c1.second < c2.second;
    }
};

I want the elements to be sorted based on the second element of pair, which this implementation is doing, but the problem is that it is using the same comparer when inserting new pairs and I get duplicates.
My question is: Is it possible to make the std::set to not allow duplicates also to order the elements based on the second element of pair?

Edit: Eliminated some code that was not necessary and changed in Compare > with <


Solution

  • Using your Comparer the set will contain only unique values of the int, since Coordinates isn't participating in the comparison at all.

    std::set uses operator < for sorting as well as equality; equality is determined as !(a<b || b<a). Therefore operator < should take into account every attribute which makes the element unique.

    You can specialize std::less for your type like this:

    namespace std {
    template<>
    struct less<pair<Coordinates, int>> {
        bool operator()(const pair<Coordinates, int>& a, const pair<Coordinates, int>& b) const {
            return tie(a.second, a.first.x, a.first.y) < tie(b.second, b.first.x, b.first.y);
        }
    };
    }
    

    Then std::set< std::pair<Coordinates, int>> positions; should work.