c++sortingstrict-weak-ordering

std::sort vector of struct invalid operator<


I have problem with strict weak ordering in the compare function in std::sort. I can't see why this would fail.

I have some nested structs:

struct date{
    int day = 1;
    int month = 1;
    int year = 2017;
};    
struct hhmmss{
    int hours = 1;
    int minutes = 1;
    int seconds = 1;
};    
struct dateAndTime {
   date d;
   hhmmss t;
};    
struct Trade
{
   /*
   other unrelevant data
   */
   dateAndTime timeClosed;
};

In my code, at some point I have a populated std::vector<Trade> which I want to sort.

My sort function:

void sortTradesByDate(std::vector<Trade>& trades){
   std::sort(trades.begin(), trades.end(), compareDateAndTime);
}

My comparison function:

bool compareDateAndTime(const Trade& t1, const Trade& t2){
   if (t1.timeClosed.d.year < t2.timeClosed.d.year)
      return true;
   else if (t1.timeClosed.d.month < t2.timeClosed.d.month)
      return true;
   else if (t1.timeClosed.d.day < t2.timeClosed.d.day)
      return true;
   else if (t1.timeClosed.t.hours < t2.timeClosed.t.hours)
      return true;
   else if (t1.timeClosed.t.minutes < t2.timeClosed.t.minutes)
      return true;
   else if (t1.timeClosed.t.seconds < t2.timeClosed.t.seconds)
      return true;
   return false;      
}

When running the function, and debuging, my first item passed to compareDateAndTime() passes after returning true on one of the statements (months). The next item returns true at hours comparison, but then I get a "Debug Assertion Failed!" with "Expression: invalid operator<".

Doing some googling, this has to do with strict weak ordering. But why does this fail when comparing int variables?


Solution

  • Your comparison function isn't implementing strict weak ordering

    Consider this scenario:

    compareDateAndTime(t1, t2) would return true.

    You should proceed to compare month if and only if year is the same.

    if (t1.timeClosed.d.year < t2.timeClosed.d.year)
        return true;
    if (t1.timeClosed.d.year > t2.timeClosed.d.year)
        return false;
    if (t1.timeClosed.d.month < t2.timeClosed.d.month)
        return true;
    if (t1.timeClosed.d.month > t2.timeClosed.d.month)
        return false;
    

    ... and so forth ...