Question

Lately, when I implement a class I create a nested namespace named operators where I add the stream operators.

I do this because I often need to use them in a namespace other than the class' namespace os I do a

using my_namespace::operators;

just where I want it and that's it.

Here I have an example with a class Point, a class Segment and their stream operators where the Segment's stream calls the Point's stream. But... I cannot compile:

Class 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

Class Segment:

#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

Main:

#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;
}

This cannot compile and I get:

../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’

If I remove namespace operators compiles correctly but as I told you, I want to avoid it.

I believe the problem has to do with calling using a namespace operators inside a another namespace operators.

Any ideas?

Was it helpful?

Solution

It is unclear why you want the operators to live in a different namespace than your types. In general the recommendation is that operators should live in the same namespace as the user defined types on which they operate. Doing so enables Argument Dependent Lookup, which in turn will help finding the correct operator when you use it (and will solve your compilation error).

If there is a real reason to have the operators in a different namespace, you can provide a tag type in that namespace and then use inheritance to force ADL to look into the nested namespace (the using-directive won't help with 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;
   }
}

Note that this is somehow of a hack, and some people will be surprised that the operators are not defined in the A namespace... it works because the set of associated namespaces for a type includes the namespace where the type is defined and also the namespaces of all of it's bases (in this case, ::A::operators is pulled due to the inheritance relationship between ::A::B and ::A::operators::tag)

NOTE: If you define the operators in the same namespace as the type, then you don't need the using-directive at all, as ADL will find them when needed.

OTHER TIPS

The problem is that you've imported the namespace into your code via using, but the library headers don't do this. So they only find the operators in the global namespace, namespace std, or via argument-dependent lookup.

You can probably work around this by doing

using namespace geom_2d::operators;

before

#include <iostream>

but this seems to me like a poor solution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top