std::reference_wrapper does not have an operator<, so the only way to do ref_wrapper<ref_wrapper is via the ref_wrapper member:
operator T& () const noexcept;
As you know, std::string is:
typedef basic_string<char> string;
The relevant declaration for string<string is:
template<class charT, class traits, class Allocator>
bool operator< (const basic_string<charT,traits,Allocator>& lhs,
const basic_string<charT,traits,Allocator>& rhs) noexcept;
For string<string this function declaration template is instantiated by matching string = basic_string<charT,traits,Allocator> which resolves to charT = char, etc.
Because std::reference_wrapper (or any of its (zero) bases classes) cannot match basic_string<charT,traits,Allocator>, the function declaration template cannot be instantiated into a function declaration, and cannot participate in overloading.
What matters here is that there is no non-template operator< (string, string) prototype.
Minimal code showing the problem
template <typename T>
class Parametrized {};
template <typename T>
void f (Parametrized<T>);
Parametrized<int> p_i;
class Convertible {
public:
operator Parametrized<int> ();
};
Convertible c;
int main() {
f (p_i); // deduce template parameter (T = int)
f (c); // error: cannot instantiate template
}
Gives:
In function 'int main()':
Line 18: error: no matching function for call to 'f(Convertible&)'
Standard citations
14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
(...)
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:
- If the original
P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
Note that this is the case with std::string()<std::string().
- The transformed
A can be another pointer or pointer to member type that can be converted to the deduced A via a qualification conversion (4.4).
See comment below.
- If
P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A.
Comment
This implies that in this paragraph:
14.8.1 Explicit template argument specification [temp.arg.explicit]/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.
the if should not be taken as a if and only if, as it would directly contradict the text quoted previously.