Reputation: 20276
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
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