Вот более простое воспроизведение:
namespace A {
struct X { };
}
namespace B {
struct Y {
A::X x;
// #1
friend std::ostream& operator<<(std::ostream& os, A::X) {
return os;
}
// #2
friend std::ostream& operator<<(std::ostream& os, Y y) {
return os << y.x; // error: no match for operator<<
}
};
}
Это из-за того, как работает поиск по имени.Когда вы объявляете и определяете функцию-друга области имен, как эта, эта функция может только быть найдена путем зависимого от аргумента поиска ее аргументов.Он никогда не обнаруживается при обычном неквалифицированном поиске.
Но функция, которую вы объявляете в #1
, фактически не находится в связанном пространстве имен ни одного из своих аргументов - функция объявлена в namespace B
, нодва аргумента в namespace std
и namespace A
соответственно.В результате, когда мы пишем os << y.x
, при обычном неквалифицированном поиске не найдено ни одного подходящего кандидата, а затем не найдено ни одного кандидата в зависимости от аргумента - #1
не находится в правильном пространстве имен.Следовательно, нет кандидатов.
Самое короткое решение - просто добавить объявление области имен пространства #1
вне struct Y
:
namespace B {
std::ostream& operator<<(std::ostream&, A::X);
struct Y { ... };
}
Теперь эта функция может быть найденаобычный неквалифицированный поиск, поэтому вызов в #2
работает.Но на самом деле, нет никакой причины объявлять #1
как функцию друга с B::Y
(это никоим образом не относится к B::Y
), так что просто объявите это внешне.Он также не очень хорошо работает как потоковый оператор, поэтому, вероятно, просто сделайте его обычной функцией.