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.