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