Symptom:
Currently, in the standard library, when some functionality for a class template is impossible or unsuitable to be implemented as a member function, it is implemented as a non-member function template. For example, std::vector has the following non-member function template defined for it:
template <class T, class Allocator>
bool operator< (const vector<T, Allocator>& x, const vector<T, Allocator>& y);
This issue is that functionality implemented in this manner is not accessible via std::reference_wrapper. For example:
#include <functional>
#include <iostream>
#include <vector>
int main() {
//std::vector<int> a, b; // Oops.
int a = 0, b = 0;
auto refa = std::ref(a);
auto refb = std::ref(b);
std::cout << (refa < refb);
}
The program compiles fine when a and b are of type int, but does not when they are of type std::vector<int> despite the fact that std::reference_wrapper<std::vector<int>> is implicitly convertible to std::vector<int>& for which an overloaded operator< is defined.
Cause:
This phenomenon turns out to be caused by the template nature of the non-member functions. According to N4296 14.8.1 [temp.arg.explicit] para. 6
Implicit conversions (Clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction.
Suggested resolution:
Define the non-member functions inline as friends of their corresponding class template. Functions defined in this manner are non-templates, and are accessible via std::reference_wrapper. For example, the overloaded operator< for std::vector could be revised as
template <class T, class Allocator = allocator<T>>
class vector {
...
friend bool operator< (const vector& x, const vector& y) { ... }
};
Final Words:
I hope to report this as a library defect to the library working group, if it can be seen as such and has not been reported already.