Поскольку Test
находится в пространстве имен B
, компиляция видит оператор в этом пространстве имен и отмечает, что у него нет соответствующей подписи.Он также пытается найти оператор в пространстве имен A, которое содержит класс, но также не может найти его там.Поскольку в пространстве имен B
уже есть такой оператор (с неверной подписью), он не будет пытаться найти его в глобальной области видимости.
Причина, по которой он не ищет глобальную, - это примерноследующее.Сначала я процитирую стандарт, а затем попытаюсь объяснить его.
Из 3.4 / 1:
... Поиск имени может связать более одного объявления с именемесли он находит имя как имя функции;говорят, что объявления образуют набор перегруженных функций (13.1).Разрешение перегрузки (13.3) происходит после успешного поиска имени.
Когда я читаю это, когда компилятор пытается найти функцию (в этом контексте ваши операторы), он сначала пытается это сделать.поиск имени, чтобы найти функцию в первую очередь.Затем он пытается выбрать правильную функцию из набора перегрузок.
Теперь из 3.4.1 / 6:
Имя, используемое в определении функции (26)который является членом пространства имен N (где только для целей представления N может представлять глобальную область видимости) должен быть объявлен перед его использованием в блоке, в котором он используется, или в одном из его включающих блоков (6.3) или,должен быть объявлен перед его использованием в пространстве имен N или, если N является вложенным пространством имен, должен быть объявлен перед его использованием в одном из вмещающих пространств имен N.
Давайте разберем это.Вы используете operator<<
в функции уровня пространства имен, поэтому этот раздел применяется.Он попытается найти этот оператор, используя приоритет в описанном выше.Ваш оператор не объявлен в текущем или вложенных блоках (это относится к вложенному {}
в вашей функции).Однако следующая часть соответствует «... должна быть объявлена до ее использования в пространстве имен N ...».Там равно на самом деле operator<<
в текущем пространстве имен (B
), поэтому он добавляет этот оператор в свой список совпадений.В B
больше нет совпадений, и поскольку область одинакового пространства имен считается наилучшей возможной близостью совпадения, она не будет рассматривать другие области.
Причина, по которой это работает, когда вы помещаетеоператор в пространство имен A заключается в том, что поскольку печатаемый элемент является членом A
, это пространство имен фактически рассматривается, поскольку оно включено в пространства имен выражения.Поскольку пространство имен A
считается , он находит соответствующее совпадение в этом пространстве имен и правильно компилирует.
Теперь, когда у него есть список возможных операторов, он пытается выполнить разрешение перегрузки для них.К сожалению, один из найденных в пространстве имен B является единственным, который он рассматривает, и он не соответствует требуемым аргументам.
В общем случае операторы вставки должны быть в том же пространстве имен, что и класс, с которым он работает.