std::reference_wrapper
не имеет operator<
, поэтому единственный способ сделать ref_wrapper<ref_wrapper
- через члена ref_wrapper
:
operator T& () const noexcept;
Как вы знаете, std::string
это:
typedef basic_string<char> string;
Соответствующее объявление для string<string
:
template<class charT, class traits, class Allocator>
bool operator< (const basic_string<charT,traits,Allocator>& lhs,
const basic_string<charT,traits,Allocator>& rhs) noexcept;
Для string<string
этот шаблон объявления функции создается путем сопоставления string
= basic_string<charT,traits,Allocator>
, который разрешается в charT
= char
и т. Д.
Поскольку std::reference_wrapper
(или любой из его (нулевых) базовых классов) не может соответствовать basic_string<charT,traits,Allocator>
, шаблон объявления функции не может быть создан в объявлении функции и не может участвоватьв перегрузке.
Здесь важно то, что нет не-шаблон operator< (string, string)
прототип.
Минимальный код, показывающий проблему
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
}
Дает :
In function 'int main()':
Line 18: error: no matching function for call to 'f(Convertible&)'
Стандартные цитаты
14.8.2.1 Вывод аргументов шаблона из вызова функции [temp.deduct.call]
Вывод аргумента шаблона выполняется путем сравнения каждого типа параметра шаблона функции (назовите его P
) стип соответствующего аргумента вызова (назовите его A
), как описано ниже.
(...)
В общем, процесс удержания пытаетсянайдите значения аргументов шаблона, которые сделают вывод A
идентичным A
(после преобразования типа A
, как описано выше).Однако есть три случая, которые допускают различие:
- Если исходный
P
является ссылочным типом, выведенный A
(т. Е. Тип, на который ссылается ссылка), может быть большес квалификацией cv, чем преобразованный A
.
Обратите внимание, что это имеет место с std::string()<std::string()
.
- Преобразованный
A
может быть другим указателем или указателем на тип элемента, который может быть преобразован в выведенное значение A
посредством преобразования квалификации (4.4).
См. комментарий ниже.
- Если
P
является классом и P
имеет форму simple-template-id , то преобразованный A
может быть производным классом выведенного A
.
Комментарий
Это означает, что в этом абзаце:
14.8.1 Явная спецификация аргумента шаблона [temp.arg.explicit] / 6
Неявные преобразования (пункт 4) будут выполняться для аргумента функции для преобразования его в типсоответствующего параметра функции , если тип параметра не содержит шаблонных параметров, которые участвуют в выводе аргумента шаблона.
, если не следует воспринимать как тогда и только тогда, когда , поскольку это прямо противоречило бы приведенному ранее тексту.