Antonio
Antonio

Reputation: 20276

Invalid operands to binary expression error (missing const) in std::sort: Why does specifying the compare operator solve it?

Considering:

#include <algorithm>
#include <vector>

struct A {
    double dummy;
    
    bool operator<(const A& a) { ///Here I am missing a `const`
        return dummy < a.dummy;
    }
};

int main()
{
    std::vector<A> a;
    a.push_back({0.9});
    a.push_back({0.4});
    std::sort(a.begin(),a.end());
    return 0;
}

This compiles fine on gcc, but on clang it gives

/usr/include/c++/v1/algorithm:719:71: error: invalid operands to binary expression ('const A' and 'const A')
    bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}

and a long list of failed instantiation. Here is my minimal example in action: https://rextester.com/VEO17629

I could finally solve it when I found Invalid operand to binary expression on std::max_element (the operator < must have a const specifier).

The curious thing is that the error goes away also if I call std::sort specifying the operator std::less<>():

std::sort(a.begin(),a.end(),std::less<>());

Why does specifying the compare operator std::less<>() solve the error?

Upvotes: 2

Views: 1333

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 117308

Why does specifying the compare operator std::less<>() solve the error?

Interestingly enough, it's only when you use std::less<void> (std::less<>) that it compiles. std::less<A> does not.

std::less<A>::operator():

constexpr bool operator()( const T& lhs, const T& rhs ) const;

The std::less<void>::operator() has a slightly different signature, not specifying const T&:

template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
  -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs));

So, the std::less<void>::operator() is free to call the non-const operator<.


The difference between g++ (libstdc++) and clang++ (libc++) can have some different explanations. One would be if libstdc++ forwards std::sort(a.begin(),a.end()) to std::sort(a.begin(),a.end(), std::less<>{}) instead of using operator< directly.

In C++14 (that you used in your demo) [alg.sorting]/1 just says: "All the operations in 25.4 have two versions: one that takes a function object of type Compare and one that uses an operator<.".

There is nothing prohibiting using std::less<void> to call operator<.

In C++20 [sort]/1 there has even been an addition, specifying exactly that behavior when no comparator is given: "Let comp be less{} and proj be identity{} for the overloads with no parameters by those names.". clang++/libc++ in C++20 mode fails to comply to this though.

Upvotes: 2

Related Questions