Overloading ostream operator (<<) for class defined within a namespace - c++

Consider bar.h:
#include <iostream>
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}
Consider bar.cc:
#include "bar.h"
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
Why can't the implementation for operator << access the private member from the Bar class? That is:
$ icpc -c bar.cc
bar.cc(5): error #308: member "foo::Bar::xx_" (declared at line 9 of "bar.h") is inaccessible
output << in.xx_ << std::endl;
^
compilation aborted for bar.cc (code 2)
I solved the problem by embedding the implementation for operator << inside the foo namespace, i.e.:
namespace foo {
std::ostream& operator<<(std::ostream& output, const foo::Bar &in) {
output << in.xx_ << std::endl;
return output;
}
}
Yet... is this the correct way of solving this problem? Isn't this approach giving away details of the implementation?

Question:
is this the correct way of solving this problem?
Answer:
Yes, it is the correct way of solving the problem.
Question:
Isn't this approach giving away details of the implementation?
Answer:
Not at all.
The line
friend std::ostream& operator <<(std::ostream& output, const Bar&);
declares the function as an external function in the namespace in which the class is defined. If the class is not defined in a namespace, the function is declared as an external function in the global namespace. Since the function is declared as a external function in the foo namespace, it MUST be defined in that namespace.
If you want that function to be a global function, outside the foo namesapce, you have to use:
namespace foo
{
class Bar;
}
std::ostream& operator <<(std::ostream& output, const foo::Bar&);
namespace foo {
class Bar {
public:
friend std::ostream& operator <<(std::ostream& output, const Bar&);
private:
int xx_;
};
}

Because your class Bar is part of the foo namespace you need to define the function within the same namespace.
If you are worried about hiding the implementation details you can still define the function in bar.cc
bar.cc
#include "foo.h"
namespace foo
{
std::ostream& operator<<(std::ostream& output, const Bar &in)
{
output << "Bar x=" << in.x << std::endl;
return output;
}
}

Related

streaming operator overloading for nested type names inside templates

The following code does not compile:
#include <type_traits>
#include <optional>
#include <iostream>
using namespace std;
namespace dbj {
template< typename K, typename V >
class top final {
static_assert(
! is_same_v<K,V>,
" to make things simpler K and V must be different types"
);
public:
// nested type names
using key_type = optional<K>;
using val_type = optional<V>;
using type = top;
private:
key_type key_{};
val_type val_{};
public:
top() = delete;
explicit top(K k, V v) : key_(k), val_(v) {}
private:
// PROBLEM A: not found by
// friend wostream & operator << (wostream & os, type top_)
friend wostream & operator << (wostream & os, key_type key_arg_ ) {
return os << L"\nK : " << key_arg_.value_or(K{});
}
// PROBLEM B: not found by
// friend wostream & operator << (wostream & os, type top_)
friend wostream & operator << ( wostream & os, val_type val_arg_ ) {
return os << L"\nV : " << val_arg_.value_or(V{});
}
// found no problem
friend wostream & operator << (wostream & os, type top_)
{
// ISSUE D: this is not looking for overloads in the immediate scope
// i.e. inside the template class
// this is first looking for operator declaration inside namespace dbj
return os << L"\n\nprinting dbj::top<K,V> : " << top_.key_ << L"," << top_.val_;
}
}; // top
} // dbj ns
using top_type = dbj::top<wstring, int>;
extern "C" int test_operator_overloading_puzzle()
{
top_type top_{ L"the key", 42 };
std::wcout << top_ << std::endl;
return 1;
}
Also available here: https://wandbox.org/permlink/jMKpn6CKFL2cyceO
Every compiler complains that within the streaming operator for type top_, no match is found for streaming top_.key (marked ISSUE D in the code above). Why can't lookup find the two streaming functions I declared directly above them?
Here's a simpler reproduction:
namespace A {
struct X { };
}
namespace B {
struct Y {
A::X x;
// #1
friend std::ostream& operator<<(std::ostream& os, A::X) {
return os;
}
// #2
friend std::ostream& operator<<(std::ostream& os, Y y) {
return os << y.x; // error: no match for operator<<
}
};
}
This is because of how name lookup works. When you declare and define a namespace-scope friend function like this, that function can only be found by argument-dependent lookup of its arguments. It is never found by regular unqualified lookup.
But the function you're declaring in #1 isn't actually in the associated namespace of any of its arguments - the function is declared in namespace B, but its two arguments are in namespace std and namespace A, respectively. As a result, when we write os << y.x, no matching candidates are found by regular unqualified lookup and then no candidates are found by argument-dependent lookup either - #1 is not in the right namespace. Hence, no candidates.
The shortest solution is to just add a namespace-scope declaration of #1 outside of struct Y:
namespace B {
std::ostream& operator<<(std::ostream&, A::X);
struct Y { ... };
}
Now, this function can be found by regular unqualified lookup, so the call in #2 works. But really, there's no reason to have declared #1 as a friend function with B::Y (it in no way refers to B::Y), so just declare it externally. It also doesn't work very well as a streaming operator, so probably just make it a regular function instead.
Just building on top of Barry's simplification of the question and then on top of his answer.
namespace {
using namespace std;
namespace A {
struct X {
// #1 --> SOLUTION to problem #1
// friend operator is here in the scope where
// name lookup can find it, declared and defined
friend wostream& operator<<(wostream& os, X) {
return os << L"A::X" ;
}
};
}
namespace B {
struct Y {
A::X x;
// #1 --> PROBLEM: name lookup can not find this
// as it is in the scope unrelated to A::X
/*
friend std::ostream& operator<<(std::ostream& os, A::X) {
return os;
}
*/
// #2
friend wostream& operator<<(wostream& os, Y y) {
// << y.x is normally found inside the
// type of x and that is A::X
return os << L"\nB::Y --> " << y.x;
}
};
}
void test_barry() {
B::Y by_;
wcout << by_;
}
}
This is for the situations when we can insert the necessary friend operator inside the nested type. Otherwise please see Barry's answer.
For further education opportunity perhaps this is a good start.

How do I overload << in std::stringstream [duplicate]

I am writing a small matrix library in C++ for matrix operations. However my compiler complains, where before it did not. This code was left on a shelf for 6 months and in between I upgraded my computer from debian etch to lenny (g++ (Debian 4.3.2-1.1) 4.3.2
) however I have the same problem on a Ubuntu system with the same g++.
Here is the relevant part of my matrix class:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
}
}
And the "implementation":
using namespace Math;
std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {
[...]
}
This is the error given by the compiler:
matrix.cpp:459: error: 'std::ostream&
Math::Matrix::operator<<(std::ostream&,
const Math::Matrix&)' must take
exactly one argument
I'm a bit confused by this error, but then again my C++ has gotten a bit rusty after doing lots of Java those 6 months. :-)
Just telling you about one other possibility: I like using friend definitions for that:
namespace Math
{
class Matrix
{
public:
[...]
friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
[...]
}
};
}
The function will be automatically targeted into the surrounding namespace Math (even though its definition appears within the scope of that class) but will not be visible unless you call operator<< with a Matrix object which will make argument dependent lookup find that operator definition. That can sometimes help with ambiguous calls, since it's invisible for argument types other than Matrix. When writing its definition, you can also refer directly to names defined in Matrix and to Matrix itself, without qualifying the name with some possibly long prefix and providing template parameters like Math::Matrix<TypeA, N>.
You have declared your function as friend. It's not a member of the class. You should remove Matrix:: from the implementation. friend means that the specified function (which is not a member of the class) can access private member variables. The way you implemented the function is like an instance method for Matrix class which is wrong.
To add to Mehrdad answer ,
namespace Math
{
class Matrix
{
public:
[...]
}
std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}
In your implementation
std::ostream& operator<<(std::ostream& stream,
const Math::Matrix& matrix) {
matrix.print(stream); //assuming you define print for matrix
return stream;
}
Assuming that we're talking about overloading operator << for all classes derived from std::ostream to handle the Matrix class (and not overloading << for Matrix class), it makes more sense to declare the overload function outside the Math namespace in the header.
Use a friend function only if the functionality cannot be achieved via the public interfaces.
Matrix.h
namespace Math {
class Matrix {
//...
};
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);
Note that the operator overload is declared outside the namespace.
Matrix.cpp
using namespace Math;
using namespace std;
ostream& operator<< (ostream& os, const Matrix& obj) {
os << obj.getXYZ() << obj.getABC() << '\n';
return os;
}
On the other hand, if your overload function does need to be made a friend i.e. needs access to private and protected members.
Math.h
namespace Math {
class Matrix {
public:
friend std::ostream& operator<<(std::ostream&, const Matrix&);
};
}
You need to enclose the function definition with a namespace block instead of just using namespace Math;.
Matrix.cpp
using namespace Math;
using namespace std;
namespace Math {
ostream& operator<<(ostream& os, const Matrix& obj) {
os << obj.XYZ << obj.ABC << '\n';
return os;
}
}
In C++14 you can use the following template to print any object which has a T::print(std::ostream&)const; member.
template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os)
{
t.print(os);
return os;
}
In C++20 Concepts can be used.
template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
{ t.print(os) };
};
template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) {
t.print(os);
return os;
}
I would like to simplify this a little with an example that overloads << to print an array.
First pass both the object types around the << operator
create a function to overload the operator as follows.
#include<iostream>
using namespace std;
void operator<<(ostream& os, int arr[]) {
for (int i = 0;i < 10;i++) {
os << arr[i] << " ";
}
os << endl;
}
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << arr;
}
if cascading of operators is also required make sure to return cout object
in the overloaded function as follows,
#include<iostream>
using namespace std;
ostream& operator<<(ostream& os, int arr[]) {
for (int i = 0;i < 10;i++) {
cout << arr[i] << " ";
}
cout << endl;
return os;
}
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 11,22,33,44,55,66,77,88,99,100 };
// cascading of operators
cout << arr << arr2;
}

Friend functions and namespaces

I'm trying to overload the << operator for a class that's part of a user-defined namespace. What's interesting is that if I remove all that namespace stuff, the program compiles and runs without a problem, but the fact that the class resides in a namespace somehow makes the compilation process for the file A.cpp fail with an error saying that I'm trying to access private data in class A (demo.cpp compiles fine). Please, take a look at my three-file program and the compilation error that I get:
demo.cpp:
#include <iostream>
#include "A.h"
int main() {
usr::A a(4);
std::cout << a << std::endl;
return 0;
}
A.h:
#ifndef A_H_
#define A_H_
#include <iostream>
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& operator<<(std::ostream& os, const usr::A& a);
};
}
#endif // A_H_
A.cpp:
#include "A.h"
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
Error:
$ g++ -c A.cpp
In file included from A.cpp:1:0:
A.h: In function ‘std::ostream& operator<<(std::ostream&, const usr::A&)’:
A.h:10:17: error: ‘int usr::A::m_x’ is private
int m_x;
^
A.cpp:7:13: error: within this context
os << a.m_x;
^
Non-qualified friend declarations always refer to members of the smallest enclosing namespace. When a class is declared in namespace usr, any non-qualified friend declaration inside that class refers to members of usr. I.e. your friend declaration declared usr::operator << as a friend.
The global ::operator << remains a non-friend in this case, which is why you get the error when you attempt to access private members of usr::A from ::operator <<.
If you want this to work, you have to either
Make your operator << a member of usr, or
Make sure the friend declaration explicitly refers to global operator << by using a qualified name ::operator << (this will also require introducing ::operator << before trying to refer to it by its qualified name).
I would suggest the first approach. If your class A is a member of namespace usr, then it is a good idea to declare all functions that handle A as members of usr as well. This will help you to avoid many problems with argument-dependent lookup (ADL) down the road.
But if for some reason you need your operator << to remain a member of global namespace, then here are the hoops you'd have to jump through to make it compile (combined into a single translation unit)
// Pre-declare `usr::A` to enable pre-declaration of our `::operator <<`
namespace usr {
class A;
}
// Pre-declare our `::operator <<`
std::ostream& operator<<(std::ostream& os, const usr::A& a);
namespace usr {
class A {
private:
int m_x;
public:
A(int x);
friend std::ostream& ::operator<<(std::ostream& os, const usr::A& a);
// Friend declaration uses qualified name - it explicitly
// refers to `::operator <<` declared above
};
}
usr::A::A(int x) : m_x(x) {}
std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << a.m_x;
return os;
}
int main() {
usr::A a(4);
std::cout << a << std::endl;
}
Under GCC you have to separate return-type and scope resolution operator (:: token) via some access modifier (reference on const or pointer).
For example, this will not compile under g++7.2.0:
std::string f(int a);
namespace NS
{
class C
{
friend std::string ::f(int a);
// scope operator ^^ is absolutely needed
}
}
But this will:
std::string f(int a);
namespace NS
{
class C
{
friend std::string const ::f(int a);
// see const keyword ^
}
}
And this will:
std::string f(int a);
namespace NS
{
class C
{
friend std::string& ::f(int a);
// see ref symbol ^
}
}

Friend function defining an ostream operator

I would like to define an ostream operator to let me easily output variables of type alglib::complex. To provide a working example without including the alglib library I'll instead overload the output of complex<double> below (this clarification because of an earlier version of the question). In the header file "my_class.h" I have
using namespace std;
#include <complex>
#include <iostream>
class my_class {
public:
ostream& operator << (std::ostream& os, complex<double> a) {
os << "(" << real(a) << "," << imag(a) << ")";
return os;
}
void output(complex<double>);
my_class() {}
~my_class() {}
};
And in the source file "my_class.cpp" I have
#include "my_class.h"
void my_class::output(complex<double> cd) {
cout << cd << endl;
}
Finally I have a main method file "run_my_class.cpp":
#include "my_class.h"
int main(int argc, const char* argv[]) {
my_class obj;
complex<double> cd=complex<double>(1.0,-1.0);
obj.output(cd);
}
I try to compile using
g++ -c my_class.cpp
but this gives me the error
my_class.h:9:62: error: ‘std::ostream& my_class::operator<<(std::ostream&, std::complex<double>)’ must take exactly one argument
ostream& operator << (std::ostream& os, complex<double> a) {
However, if I define the operator as a friend, namely friend ostream& operator << (std::ostream& os, complex<double> a), it compiles and I compile the main method:
g++ run_my_class.cpp my_class.o -o run_my_class
And it works as it should. However this is not what it seems the friend keyword is for. Is there a better way to make this work?
Since operator << will be called on an std::ostream, you cannot define this procedure as a member function for my_class, you have to define it as a global function, since it's an operation for std::ostream, not my_class.
By putting the friend keyword into the declaration, you are saying that you want to declare the operator << as a friend global function (not a member function!). The C++ standard lets you put the definition of the friend function there, but it won't be a member function. It is the same as the following, which is more clear:
#include <complex>
#include <iostream>
class my_class {
public:
friend ostream& operator << (std::ostream& os, complex<double> a);
void output(complex<double>);
my_class() {}
~my_class() {}
};
std::ostream& operator << (std::ostream& os, complex<double> a) {
os << "(" << real(a) << "," << imag(a) << ")";
return os;
}
As it was already pointed out in the comments, the usage of friend is not necessary here.
Irrelevant to the question, but please be aware that resolving namespaces in a header file is generally a really-really bad idea, since all other files including it will implicitly resolve that namespace too. It can easily lead to vexing compilation errors in the long run.
I wouldn't call it a better way but a more clear way.
Here's your stream operator again:
ostream& operator << (std::ostream& os, complex<double> a) {
os << "(" << real(a) << "," << imag(a) << ")";
return os;
}
Its first parameter is the output stream. Since you do not have access to the output stream, you can't use the output stream operator as a member function unless you make it a friend of the class.
If you want to want to avoid using friend you can always define it as a function external to the class, and that is the most common way.

Scoping rules in operator overloading

Considering the following code:
namespace myNS {
class MyClass {
//.....
};
} //end of namespace myNS
using namespace myNS;
//overloading of '<<' operator
std::ostream &myNS::operator<<(std::ostream &os, MyClass &c){ /*....*/ }
In the last line, why is &myNS:: needed?
& is needed because, conventionally, streaming operators return a reference to the stream to allow them to be chained:
stream << something << something_else;
with something_else being passed to the stream reference returned by stream << something.
myNS:: is needed if this operator is supposed to be scoped inside the namespace, in which case there must also be a previous declaration inside the namespace. If you want the operator to be in the current namespace (presumably the global namespace in this example), then it's not needed.
Since std::ostream& operator<<(std::ostream&, MyClass&) is not declared inside the myNS namespace, there is no need to qualify it. This equivalent code is legal:
#include <iostream>
namespace Foo
{
class Bar{};
}
using namespace Foo;
std::ostream& operator<<(std::ostream& o, const Bar&) { return o;}
int main()
{
Foo::Bar b;
std::cout << b << "\n";
}