operator << must take exactly one argument
The problem is that you define it inside the class, which
a) means the second argument is implicit (this
) and
b) it will not do what you want it do, namely extend std::ostream
.
You have to define it as a free function:
class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
A friend function is not a member function, so the problem is that you declare operator<<
as a friend of A
:
friend ostream& operator<<(ostream&, A&);
then try to define it as a member function of the class logic
ostream& logic::operator<<(ostream& os, A& a)
^^^^^^^
Are you confused about whether logic
is a class or a namespace?
The error is because you've tried to define a member operator<<
taking two arguments, which means it takes three arguments including the implicit this
parameter. The operator can only take two arguments, so that when you write a << b
the two arguments are a
and b
.
You want to define ostream& operator<<(ostream&, const A&)
as a non-member function, definitely not as a member of logic
since it has nothing to do with that class!
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.number;
}
I ran into this problem with templated classes. Here's a more general solution I had to use:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// Friend means operator<< can use private variables
// It needs to be declared as a template, but T is taken
template <class U>
friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}
// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
obj.toString(os);
return os;
}
Now: * My toString() function can't be inline if it is going to be tucked away in cpp. * You're stuck with some code in the header, I couldn't get rid of it. * The operator will call the toString() method, it's not inlined.
The body of operator<< can be declared in the friend clause or outside the class. Both options are ugly. :(
Maybe I'm misunderstanding or missing something, but just forward-declaring the operator template doesn't link in gcc.
This works too:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// For some reason this requires using T, and not U as above
friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
{
obj.toString(os);
return os;
}
}
I think you can also avoid the templating issues forcing declarations in headers, if you use a parent class that is not templated to implement operator<<, and use a virtual toString() method.