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) будут выполняться для аргумента функции, чтобы преобразовать его в тип соответствующего параметра функции, если тип параметра не содержит параметров шаблона, которые участвуют в выводе аргумента шаблона.
if не следует воспринимать как если и только если, так как это будет прямо противоречить тексту, процитированному ранее.
person
curiousguy
schedule
14.12.2011