Напомним, что std::string
не является самостоятельным типом, это действительно специализация шаблона класса - std::basic_string<char>
. Очень важной деталью является то, что потенциал перегрузки для потоковой std::string
не принимает std::string const&
аргумент, это function template, что выводит std::basic_string const&
: Шаблон вычет
template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str);
никогда не считает преобразования. Поиск имени найдет этот шаблон функции, а затем отменит его как нежизнеспособный из-за отказа дедукции. S
не является basic_string<CharT, Traits, Allocator>
для любых таких типов, поэтому мы закончили. Единственными жизнеспособными операторами потока будут все интегральные, из которых bool
- лучший матч.
Если специально была функция с подписью:
std::ostream& operator<<(std::ostream&, std::string const&);
Тогда вызов будет неоднозначным - вы получите два определяемые пользователем преобразования, которые были бы то же самое ранжируются.
Это легко проверить с помощью собственных функций, а не миллион перегрузок для operator<<
:
void foo(bool); // #1
void foo(std::string); // #2
void bar(bool); // #3
template <class C, class T, class A>
void bar(std::basic_string<C,T,A>); // #4
foo(S{}); // error: ambiguous
bar(S{}); // calls #3
Просто придираться, никогда ничего не неявно.Типы неявно преобразуются, но * cast * означает * явное преобразование *. – StoryTeller
@StoryTeller Спасибо, хорошо знать конкретную терминологию. Я отредактировал свой вопрос. – YSC