This question is inspired by Issue with std::reference_wrapper. Let' say, for example, operator<
for std::vector
. It's defined as a function template as
template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
const vector<T,Alloc>& rhs );
As a result, implicit conversion of function argument to the type of the corresponding function parameter is denied (basically because of its template nature). This greatly reduces the usefulness and convenience of std::reference_wrapper
. For example, you cannot use std::sort
on std::vector<std::reference_wrapper<std::vector<int>>>
.
On the other hand, all the problems are solved only if operator<
is defined as a non-template Koenig operator like
template <...>
class vector ... {
friend bool operator<(const vector& a, const vector& b) {...}
};
I'm wondering why the standard library has adopted the former approach instead of this?
Consider this code (A.h):
template <class T>
class A {
public:
T m_x;
friend bool operator<(const A & lhs, const A & rhs) {
return lhs.m_x < rhs.m_x;
}
};
And main.cpp:
#include "A.h"
namespace buddy {
bool operator<(const A<double> & lhs, const A<double> &rhs) {
return lhs.m_x > rhs.m_x;
};
}
using namespace buddy;
int main(int argc, char ** argv) {
A<double> a1;
A<double> a2;
a1 < a2;
return 0;
}
This code does not compile:
main.cpp:14:5: error: ambiguous overload for ‘operator<’ (operand types are ‘A’ and ‘A’)
a1 < a2;
The reason of course is that both of the operator<'s are exact matches. On the other hand, if we change the first operator< to (defined outside the class):
template <class T>
bool operator<(const A<T> & lhs, const A<T> & rhs) {
return lhs.m_x < rhs.m_x;
}
The compiler stops complaining: it's now a competition between an exact match, and a function template, so the exact match is used.
If operator< was defined in the fashion that you're suggesting, there would be no reasonable way for users of std::vector to redefine the behavior of operator<, short of specializing std::vector themselves, which is a lot more work.
In conclusion, the standard writers elected to make it easier to overload operator<, than to provide an operator< that might be more useful in certain situations. I think they made the right choice.