Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

overloaded operator< on pair not being used in sort

Tags:

c++

sorting

I have overloaded the less than operation for pair<int,int>, so that I can sort a vector in a particular manner. I want it to be in ascending order according to the first key of a pair, and if the first keys are equal, then I'd want it in descending order according to the second key.

The issue is that the sort function doesn't seem to be using the overloaded < operator, but if < is called on 2 pairs, the output returned is what I expect. I have attached a snippet of code below which I'm using for testing:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
bool operator<(pair<int, int> &a, pair<int, int> &b)
{
    if (a.first < b.first) return true;
    else if ((a.first == b.first) && (a.second > b.second)) return true;
    return false;
}

int main() {
    vector<pair<int, int>> test {make_pair(1,10), make_pair(3,4), make_pair(3,8),  make_pair(6, 23), make_pair(1,6)};
    sort(test.begin(), test.end());
    for (int i = 0; i < test.size(); i++)
      cout << test[i].first << " - " << test[i].second << "  ";
    cout << endl;
    auto a = make_pair(3,4);
    auto b = make_pair(3,8);
    cout << (a < b) << endl;
    return 0;
}

The input vector is {(1,10), (3,4), (3,8), (6,23), (1,6)}.

I expect the output to be {(1,10), (1,6), (3,8), (3,4), (6,23)}.

Obtained output is {(1,6), (1,10), (3,4), (3,8), (6, 23)}.

As you can see, the obtained output is the one you'd get by using the standard < operator without overloading. So I thought that this might be an issue, and checked (3,4) < (3,8). In this case, the answer was returned as false, in accordance to my overloaded operator. So where am I going wrong? Why isn't sort being affected by the overloaded operator? There are various questions on SO about similar issues, but couldn't find any that helped.

like image 868
therainmaker Avatar asked Sep 16 '15 08:09

therainmaker


2 Answers

There's already an operator< defined for pairs in the std namespace, and that's the one that's found by the version of std::sort that you are using. Your overload is never found. Use a named predicate instead:

struct MyPairComparator
{
    bool operator()(const std::pair<int, int> & a,
                    const std::pair<int, int> & b) const
    {
        // ...
    }
};

sort(test.begin(), test.end(), MyPairComparator());    // ADL, maybe
//                             ^^^^^^^^^^^^^^^^^^

Also, the predicate should be callable with constant values, so either take the arguments by value or by const reference.

Note that sort lives in the std namespace. By contrast, when you use the < expression in main, your own overload in the global namespace is indeed found.

like image 160
Kerrek SB Avatar answered Nov 02 '22 12:11

Kerrek SB


It seems you use a C++11 compiler, correct and make it easier using lambda functions. Something like

sort(test.begin(), test.end(), [](const pair<int, int> & a, const pair<int, int> & b) {
    if (a.first < b.first) return true;
    else if ((a.first == b.first) && (a.second > b.second)) return true;
    return false;
});
like image 28
Shreevardhan Avatar answered Nov 02 '22 11:11

Shreevardhan