namespace and operator << overload

I'm having a problem overloading the << operator when I use a namespace.

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace XYZ
{
    class OBJTYPE
    {	// class members

	void Format (ostream & os) const;

	public:
        // member functions

 	friend ostream & operator << (ostream & os, const XYZ::OBJTYPE & objtype);
    };
};


1
2
3
4
5
6
7
8
9
using namespace XYZ;
void OBJTYPE::Format (ostream & os) const
{  // formatting logic
}

ostream & operator << (ostream & os, const XYZ::OBJTYPE & objtype)
{    objtype.Format (os);
     return os;
}


If I make Format() public, the compiler is happy.
If Format() is private, the compiler complains that it's inaccessible.
I really don't want to make Format() public.
Since operator << is a friend function, shouldn't Format() be accessible even if it's private?

What am I missing?
Last edited on
I believe this SO post is relevant:
https://stackoverflow.com/questions/4757871/gcc-failes-to-compile-operator-definition-with-prefixed-namespace
the standard wrote:
The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope (either before or after the class declaration granting friendship).

In other words, it's not matching your friend declaration to the definition simply by "using namespace XYZ;" because the standard apparently explicitly prevents that. (Why? I dunno.)
(I think, I'm not a language lawyer.)

I think you gotta do this:
1
2
3
4
5
6
7
namespace XYZ
{
    ostream & operator << (ostream & os, const XYZ::OBJTYPE & objtype)
    {    objtype.Format (os);
         return os;
    }
}
but I imagine you already thought of that.

Definitely a funny oddity.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

namespace XYZ {

class OBJTYPE {
private:
    // class members
    void Format (std::ostream & os) const;
public:
    // member functions
    OBJTYPE(){std::cout << "Bingo!!\n";}
    friend std::ostream & operator << (std::ostream & os, const OBJTYPE & objtype);
};

void OBJTYPE::Format (std::ostream & os) const
{  // formatting logic
    std::cout << "Formatting done\n";
}

std::ostream & operator << (std::ostream & os, const OBJTYPE & objtype)
{
    objtype.Format (os);
    return os;
}

}; // <-- END OF NAMESPACE

using namespace XYZ; // <-- MUST HAVE, TRY WITHOUT

int main()
{
    OBJTYPE obj;
    std::cout << obj;
    
    //obj.Format( etc); ... error inaccessible
    
    return 0;
}


Bingo!!
Formatting done
Program ended with exit code: 0
What am I missing?
Ganado is right, you cannot use "using namespace XYZ;" for a friend function.

using namespace ...; and hence removing the namespace isn't a good habit anyway...
If you take the friend function outside the namespace the program fails for several reasons. Try it.

If a program is written such that a namespace is specified the using namespace line is obvious. Neither of those two are bad habits. They naturally follow from the appropriate/valid use of namespace.

The usual aversion to namespace-ing on this site applies to using namespace std; which some just can't get over in ramming into beginners.

OP wanted a certain functionality and got it. There's no big deal AFAICS.

Ganado actually hit upon the idea of how to solve it but simply didn't extend the namespace to the whole class. There is no reason not to do just that. In fact it solves the problem raised by the OP as the program demonstrates.
regarding
againtry wrote:
 
using namespace XYZ; // <-- MUST HAVE, TRY WITHOUT 
it is just fine without, all you need is to fully name OBJTYPE, as in
1
2
3
int main()
{
    XYZ::OBJTYPE obj;
againtrys code works as posted, however, it's going to be problematic.

He included the implementation of operator << and OBJTYPE::Format() (lines 15-24) inside the namespace declaration. Assuming the declaration of OBJTYPE and it's enclosing namespace declaration are in a .h file, that's going to cause multiply defined symbols to the linker assuming the .h file is included in multiple places.

However, putting the implementation of the operator inside a namespace declaration in the .cpp file does work and avoids multiply defined symbols.

In the .cpp file:
1
2
3
4
5
6
7
8
namespace XYZ
{
std::ostream & operator << (std::ostream & os, const OBJTYPE & objtype)
{
    objtype.Format (os);
    return os;
}
}


@gando - Thanks for the SO link. That was helpful.
I confess, I don't actually understand why this works and, in the light of another thread where I got a hammering, I admit that I don't know whether it is good practice or not. (Ignore the using namespace std; bit.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;

// Presumably this bit goes in a header file

namespace XYZ
{
    class OBJTYPE;
    ostream & operator << (ostream & os, const OBJTYPE & objtype);    // declaration only


    class OBJTYPE
    {   // class members

        void Format (ostream & os) const;    // private by default
        public:
        // member functions


        friend ostream & operator << (ostream & os, const XYZ::OBJTYPE & objtype);
    };

}





// Somewhere else

void XYZ::OBJTYPE::Format (ostream & os) const
{
   os << "Here";
}


ostream & XYZ::operator << (ostream & os, const XYZ::OBJTYPE & objtype)
{
   objtype.Format (os);
   return os;
}


int main()
{
   XYZ::OBJTYPE ob;
   cout << ob;
}
Last edited on
All I have done is treated the class as anyone normally would, including a private Format method, then placing it in a namespace. It’s as simple as that.

If you want to use anything in that namespace, then use using ..., or use :: , please yourself.

I was well aware before I posted that the header and implementation files aren’t separate, but faulting that consideration is nonsense. There is absolutely nothing to gain in following that line without concrete proof.

In any case, even if it was right, which it isn’t I doubt whether too many real programmers have time enough to get down in the weeds and sweat too much about the niceties of an armchair linker. If they did they would find cppreference is seriously flawed, which it isn’t :)
Last edited on
lastchance,
I believe it works because adding that declaration on line 9 fulfills the following emphasized text:
the standard wrote:
The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope (either before or after the class declaration granting friendship).
(And of course, you namespace-scoped line 37)
Last edited on
it is just fine without, all you need is to fully name OBJTYPE,

What Cubbi should have said is
it is just fine without provided you make the obvious necessary change elsewhere
.
Topic archived. No new replies allowed.