c++ - 嵌套命名空间中的流运算符重载

标签 c++ namespaces operator-overloading stream-operators

最近,当我实现一个类时,我创建了一个名为 operators 的嵌套命名空间,我在其中添加了流运算符。

我这样做是因为我经常需要在类的命名空间 os 以外的命名空间中使用它们

using my_namespace::operators;

就在我想要的地方,仅此而已。

这里我有一个示例,其中包含类 Point、类 Segment 及其流运算符,其中 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’

如果我删除 namespace 运算符编译正确但正如我告诉你的,我想避免它。

我认为问题与在另一个命名空间运算符中使用命名空间运算符进行调用有关。

有什么想法吗?

最佳答案

目前还不清楚为什么您希望运算符位于与您的类型不同的 namespace 中。一般而言,建议运算符应与其操作的用户定义类型位于同一 namespace 中。这样做会启用 Argument Dependent Lookup,这反过来将有助于在您使用它时找到正确的运算符(并将解决您的编译错误)。

如果有一个真正的理由让运算符在不同的命名空间中,您可以在该命名空间中提供一个标记类型,然后使用继承来强制 ADL 查看嵌套的命名空间(使用-指令对 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;
   }
}

请注意,这在某种程度上是一种 hack,有些人会惊讶于运算符未在 A 命名空间中定义...它之所以有效,是因为类型的关联命名空间集包括定义类型的命名空间及其所有基的命名空间(在本例中,由于 ::A::之间的继承关系,::A::operators 被拉出B::A::operators::tag)

注意:如果您在与类型相同的 namespace 中定义运算符,那么您根本不需要使用指令,因为 ADL 会找到它们需要时。

关于c++ - 嵌套命名空间中的流运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15767750/

相关文章:

c++ - 如何使用 ostream_iterator 检查 copy_if 是否对范围内的任何内容返回 true?

C++内存泄漏检测方法

c++ - 我的成员模板函数声明有什么问题?

Javascript + 命名空间 + FF 问题

c++ - 使用模板的运算符重载

运算符 '<' 的 C++ 重载并非每次都被使用

c++ - 如何为没有 clone() 成员的类编写句柄?

xml - 使用动画、脚本等将 SVG 字符串插入 *X*HTML 的正确方法

c++ - 将 ctype 宏转换为 C++ 常量的方法

模板类上的 C++ 运算符重载