Перегрузка потокового оператора во вложенном пространстве имен

В последнее время, когда я реализую класс, я создаю вложенное пространство имен операторы где я добавляю операторы потока.

Я делаю это, потому что мне часто нужно использовать их в пространстве имен, отличном от пространства имен класса, или я делаю

using my_namespace::operators;

только там, где я хочу это и все.

Здесь у меня есть пример с классом Point, классом Segment и их операторами потока, где поток Сегмента вызывает поток Point. Но … я не могу скомпилировать:

Класс Точка:

#ifndef POINT_HPP
#define POINT_HPP

#include <iostream>

namespace geom {

class Point
{
public:
Point(int x_, int y_) : x(x_), y(y_) {};
int x;
int y;
};

namespace operators {
std::ostream& operator<<(std::ostream& out, const Point& p)
{
out << "(" << p.x << ", " << p.y << ")";
return out;
}
} // ~ namespace geom::operators
} // ~ namespace geom

#endif // ~ POINT_HPP

Сегмент класса:

#ifndef SEGMENT_HPP
#define SEGMENT_HPP

#include <iostream>
#include "point.hpp"
namespace geom_2d {

class Segment
{
public:
Segment(const geom::Point& a_, const geom::Point& b_) : a(a_), b(b_) {};
geom::Point a;
geom::Point b;
};

namespace operators {
std::ostream& operator<<(std::ostream& out, const Segment& p)
{
using namespace geom::operators;
out << "[" << p.a << ", " << p.b << "]";
return out;
}

} // ~ namespace geom_2d::operators
} // ~ namespace geom_2d

#endif // ~ SEGMENT_HPP

Главный:

#include <iostream>
#include "segment.hpp"#include "point.hpp"
using namespace geom_2d::operators;

int main()
{
geom::Point p1(3, 5);
geom::Point p2(1, 6);
geom_2d::Segment s(p1, p2);

std::cout << s << std::endl;

return 0;
}

Это не может скомпилировать, и я получаю:

../segment.hpp:21: error: no match for ‘operator<<’ in ‘std::operator<< [with _Traits = std::char_traits<char>](((std::basic_ostream<char, std::char_traits<char> >&)((std::ostream*)out)), ((const char*)"[")) << p->geom_2d::Segment::a’

Если я удаляю операторы пространства имен правильно, но, как я уже говорил, я хочу этого избежать.

Я считаю, что проблема связана с вызовом с использованием операторов пространства имен внутри других операторов пространства имен.

Есть идеи?

1

Решение

Неясно, почему вы хотите, чтобы операторы жили в другом пространстве имен, чем ваши типы. В целом, рекомендуется, чтобы операторы жили в том же пространстве имен, что и пользовательские типы, с которыми они работают. Это активирует Argument Dependent Lookup, что, в свою очередь, поможет найти правильный оператор, когда вы его используете (и решит вашу ошибку компиляции).

Если есть реальный Для того чтобы операторы находились в другом пространстве имен, вы можете указать тип тега в этом пространстве имен и затем использовать наследование, чтобы заставить ADL просматривать вложенное пространство имен (директива using не поможет с ADL):

namespace A {
namespace operators {
struct tag {};
}
struct B : operators::tag {};
namespace operators {
std::ostream& operator<<(std::ostream& out, const ::A::B& obj) { ... }
}
}
namespace C {
void foo() {
::A::B b;
std::cout << b;
}
}

Обратите внимание, что это каким-то образом взломать, и некоторые люди будут удивлены, что операторы не определены в A пространство имен … это работает, потому что набор связанных пространств имен для типа включает пространство имен, в котором определен тип, а также пространства имен всех его баз (в данном случае, ::A::operators тянет из-за наследственных отношений между ::A::B а также ::A::operators::tag)

НОТА: Если вы определяете операторы в том же пространстве имен, что и тип, то вы не нужна директива using, так как ADL найдет их при необходимости.

5

Другие решения

Проблема в том, что вы импортировали пространство имен в свой код через using, но заголовки библиотеки не делают этого. Таким образом, они находят операторы только в глобальном пространстве имен, пространстве имен stdили через аргумент-зависимый поиск.

Вы, вероятно, можете обойти это, выполнив

using namespace geom_2d::operators;

до

#include <iostream>

но это кажется мне плохим решением.

2

По вопросам рекламы [email protected]