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

Jun 4, 2011 at 3:59pm

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;
}
Jun 4, 2011 at 4:08pm
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;
}
Jun 4, 2011 at 4:19pm
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?
Jun 4, 2011 at 4:23pm
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..
Jun 4, 2011 at 4:25pm
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 Jun 4, 2011 at 4:32pm
Jun 4, 2011 at 4:53pm
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 Jun 4, 2011 at 4:57pm
Jun 4, 2011 at 4:56pm
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
Jun 4, 2011 at 5:46pm
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.



Jun 4, 2011 at 6:34pm
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 Jun 4, 2011 at 6:36pm
Jun 4, 2011 at 9:03pm
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 Jun 4, 2011 at 9:05pm
Topic archived. No new replies allowed.