must embed operator<<() implementation when using namespaces?


Must I embed or is there a way to break out the implementation?

Of course, if I embed the implementation on Line 9, it works - however, I prefer to break it out when I can.

I expect a nutty reason about not able to scope somehow as the reason why I must embed.

Please prove me wrong. TY.
(if it makes a difference at all, I am using gcc on Ubuntu)

junk.cpp:15: error: ‘std::ostream& foo::operator<<(std::ostream&, const foo::X&)’ should have been declared inside ‘foo’


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
#include <iostream>

using namespace std;

namespace foo {
  class X {
    public:
      X( int i ) : m_i( i ) { }
      friend ostream& operator<<( ostream& os, const X& x );
    private:
      int m_i;
  };
}

ostream& foo::operator<<( ostream& os, const foo::X& x )
{
  os << x.m_i;
  return os;	
}

main()
{
  foo::X x( 7 );
  cerr << x << endl;
  return 0;
}
I'm sure that error means that we need a declaration of the friend function in the foo namespace (not a definition/implementation)
This should work;
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
#include <iostream>

using namespace std;

namespace foo {
  
  class X {
    public:
      X( int i ) : m_i( i ) { }
      friend ostream& operator<<( ostream& os, const X& x );
    private:
      int m_i;
  };
  
 //declaration 
 ostream& operator<<( ostream& os, const X& x );
}

ostream& foo::operator<<( ostream& os, const foo::X& x )
{
  os << x.m_i;
  return os;    
}

int main()
{
  foo::X x( 7 );
  cerr << x << endl;
  return 0;
}
excellent - works great! (I'm a bit rusty on iostream)

tyvm, guestguikan!

btw, do you happen to know why we need both Line 10 and Line 16?
I suppose Line 10 doesn't count as a declaration?

also, under convention, should operator<<() live in foo or should it be global space like on Line 18?
It compiled without complaining on VC++..
I looked at the standard and found (section 11.4, part 9)
If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior
declaration is looked up without considering scopes that are outside the innermost enclosing non-class
scope. For a friend function declaration, if there is no prior declaration, the program is ill-formed. For a
friend class declaration, if there is no prior declaration, the class that is specified belongs to the innermost
enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a
matching declaration is provided in the innermost enclosing nonclass scope.
section 9.8 says
A class can be defined within a function definition; such a class is called a local class.
though so that should not apply to a namespace..
holy smolly - gotta read that about 10x and see if my brain can digest...

edit: can anyone actually implement according to those specs? I can't even tell if VC++ or gcc is right, after reading it 10x!

edit:
For a friend function declaration, if there is no prior declaration, the program is ill-formed.

hmm... ...have to declare it earlier? maybe I should try...
Last edited on
btw, do you happen to know why we need both Line 10 and Line 16?
I suppose Line 10 doesn't count as a declaration?

correct.
Also when an unqualified friend function (not qualified with a namespace) is given like that - the compiler assumes that the firend function is in the nearest enclosing namespace of the class - hence the need to
declare the friend function in the foo namespace (as that is the nearest enclosing namespace)


To put the friend function in the global namespace - this should do the trick:
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
#include <iostream>

using namespace std;

 //forward declaration of foo namespace  and foo::X class
 namespace foo
 {
   class X;
  }
 
 
 //global << overload declaration
 ostream& operator<<( ostream& os, const foo::X& x );

namespace foo {
  
  class X {
    public:
      X( int i ) : m_i( i ) { }
      
      //make global overload a friend - notice the ::
      friend ostream& ::operator<<( ostream& os, const X& x );
    private:
      int m_i;
  };
  
}


//actual definition of the global function
ostream& operator<<( ostream& os, const foo::X& x )
{
  os << x.m_i;
  return os;    
}



int main()
{
  foo::X x( 7 );
  cerr << x << endl;
  return 0;
}



also, under convention, should operator<<() live in foo or should it be global space


I'm not sure on this one .....
Last edited on
Please correct me.
should it be global space like on Line 18?
That is not global space ostream& foo::operator<< it is in namespace foo.

To make it global
1
2
3
4
namespace foo{
	class A; //forward declaration
}
std::ostream& operator<<(std::ostream& out, const foo::A& a);

1
2
3
4
5
6
7
namespace foo{
	class A{
	public:
		friend std::ostream& ::operator<< //global namespace
		(std::ostream& out, const A& a); 
	};
}

However I think that you should see that friend operator as a member of A, so it should be in namespace foo.
Or you could avoid the friend (providing a A::print method), and put it in the global.

Also, main must return int
The simplest way to remember it is that

 
friend std::ostream& operator<<( std::ostream&, const Foo& );


only says that said function is considered a friend of Foo (if put inside Foo). It does not actually declare the function. Hence why you need the actual declaration.



thx guestgulkan, hamsterman, ne555, jsmith for your additional comments

I've been googling around for answers on the proper scope for operator<<() and haven't found any satisfactory answers yet - some people have actually tried to make it part of std!

On one hand, I think that it should be in global namespace (or std) since operator<<() for ostreams should have consistent semantics from the highest levels.

On the other hand, I've seen comments that we shouldn't pollute the global namespace; though I'd be very afraid of code which subverts the meaning of operator<<() for ostreams for some particular, non-standard usage.

I wonder if the designers of iostream have implied any preferences for users...
Last edited on
I think you are worrying too much.
AFAICS you aren't polluting it because your class is in a namespace. The only problem could be that another provider uses the same name for its namespace and the same name for the class.
::operator<<(std::cout, foo::A()); defeats the purpose of operator overloading, so it does not matter where it is located as long as there is only one.
You could also consider
1
2
3
4
5
6
7
namespace io_ops{
  template<class T>
  std::ostream& operator<<(std::ostream &out, const T &x){
    x.print(out);
    return out;
  }
}


The same could be say of the operators < > <= >=, == != or + * / -
while < could be a method or be defined in the foo namespace, > <= >= will be in std::rel_ops
Last edited on
Topic archived. No new replies allowed.