ПРИМЕЧАНИЕ: поиск перегруженных операторов существенно отличается от поиска функций-членов класса, как предлагается другими комментариями / ответами. См. Этот ответ для ознакомления с правилами поиска имени для перегруженных операторов.
В вашем первом примере std::wcout << a
внутри X::f()
поиск имени находит:
- Квалифицированный поиск для функций-членов левого операнда:
std::wostream
имеет функцию-член operator<<
. - Неквалифицированный поиск: текущая область находится в пространстве имен
X
, поэтому X::operator<<
найден, и мы остановимся здесь. Этот этап подходит только для проверки родительских пространств имен, если имя не найдено. - Поиск, зависящий от аргументов: аргументы
std::wcout
и Y::a
, поэтому пространства имен ADL std
и Y
.
Таким образом, набор перегрузки состоит из:
- (QL) Все функции-члены
std::wostream::operator<<
. - (UL ) Все свободные функции
X::operator<<
. - (ADL) Все свободные функции
std::operator<<
- (ADL) Все бесплатные функции
Y::operator<<
(или будут, если бы они были).
и ничего больше.
Ни один из них не находит соответствия для типа аргумента Y::A
, поэтому компиляция не удалась.
Когда вы удаляете X::operator<<
, неквалифицированный шаг поиска ничего не находит в X
, поэтому он выглядит в родительское пространство имен, рекурсивно. Затем обнаруживается ::operator<<
, и эта функция входит в набор перегрузки, и компиляция завершается успешно.
Чтобы избежать этой проблемы, обычной процедурой является помещение свободных перегруженных операторов пользовательских типов в то же пространство имен, что и тип был определен, поэтому в этом случае вы должны выполнить:
namespace Y
{
inline std::wostream & operator<<(std::wostream & stream, const A & msg) { .... }
}
, и тогда шаг ADL найдет эту функцию, даже если неквалифицированный шаг поиска также найдет X::operator<<
.
Во втором примере точное значение using namespace Z;
:
При поиске безоговорочного имени имена появляются так, как если бы они были объявлены в ближайшем окружающем пространстве имен, которое содержит как директиву using, так и назначенное пространство имен.
Ближайшее вмещающее пространство имен, содержащее как X
, так и Z
, является глобальным пространством имен, поэтому имена ведут себя так, как будто в глобальном пространстве имен для фазы безусловного поиска.
Следовательно, этот процесс существенно не отличается от моего анализа для вашего первого случая, и только X::operator<<
обнаруживается при неквалифицированном поиске. Опять же, это можно исправить, включив нужную перегрузку в Y
, чтобы она была найдена ADL.