Overloading Output operator for a class template in a namespace - c++

I've this program
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std ;
#if 0
namespace skg
{
template <class T>
struct Triplet ;
}
template <class T>
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t) ;
#endif
namespace skg
{
template <class T>
struct Triplet
{
// friend ostream& ::operator<< <> (ostream& os, const Triplet<T>& p_t) ;
private:
T x, y, z ;
public:
Triplet (const T& p_x, const T& p_y, const T& p_z)
: x(p_x), y(p_y), z(p_z) { }
} ;
}
template <class T>
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
{
os << '(' << p_t.x << ',' << p_t.y << ',' << p_t.z << ')' ;
return os ;
}
namespace {
void printVector()
{
typedef skg::Triplet<int> IntTriplet ;
vector< IntTriplet > vti ;
vti.push_back (IntTriplet (1, 2, 3)) ;
vti.push_back (IntTriplet (5, 5, 66)) ;
copy (vti.begin(), vti.end(), ostream_iterator<IntTriplet> (cout, "\n")) ;
}
}
int main (void)
{
printVector() ;
}
Compilation fails because compiler could not find any output operator for skg::Triplet. But output operator does exist.
If I move Triplet from skg namespace to global namespace everything works fine. what is wrong here ?

You need to move your implementation of operator<< into the same namespace as your class. It's looking for:
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
But won't find it because of a short-coming in argument-dependent look-up (ADL). ADL means that when you call a free function, it'll look for that function in the namespaces of it's arguments. This is the same reason we can do:
std::cout << "Hello" << std::endl;
Even though operator<<(std::ostream&, const char*) is in the std namespace. For your call, those namespaces are std and skg.
It's going to look in both, not find one in skg (since yours is in the global scope), then look in std. It will see possibilities (all the normal operator<<'s), but none of those match. Because the code running (the code in ostream_iterator) is in the namespace std, access to the global namespace is completely gone.
By placing your operator in the same namespace, ADL works. This is discussed in an article by Herb Sutter: "A Modest Proposal: Fixing ADL.". (PDF). In fact, here's a snippet from the article (demonstrating a shortcoming):
// Example 2.4
//
// In some library header:
//
namespace N { class C {}; }
int operator+( int i, N::C ) { return i+1; }
// A mainline to exercise it:
//
#include <numeric>
int main() {
N::C a[10];
std::accumulate( a, a+10, 0 ); // legal? not specified by the standard
}
Same situation you have.
The book "C++ Coding Standards" by Sutter and & Alexandrescu has a useful guideline:
Keep a type and its nonmember function interface in the same namespace.
Follow it and you and ADL will be happy. I recommend this book, and even if you can't get one at least read the PDF I linked above; it contains the relevant information you should need.
Note that after you move the operator, you'll need your friend directive (so you can access private variables):
template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);
And ta-da! Fixed.

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;
}

cannot access private members in friend ostream

I tried to make friend ostream function. The compiler say i cannot access private member of the class, even though i declared it as friend. I read a similar question and it say the problem is with the namespcaes.(the question: C++ friend function can't access private members)
My Code is below:
header:
#include <iostream>
#include <string>
//using namespace std;
namespace biumath
{
#ifndef BIUMATH_H
#define BIUMATH_H
class Assignment
{
private:
int **m_varArray;
int m_rowsOfVarArray;
public:
Assignment(); //1
Assignment(char symbol, double value); //2
bool containsValueFor(char symbol) const; //3
double valueOf(char symbol) const; //4
void add(char symbol, double val); //5
friend std::ostream& operator<< (std::ostream& out,
const Assignment& assignment);
};
}
#endif
cpp:
#include <iostream>
#include "biumath.h"
using namespace biumath;
using std::cout;
using std::endl;
ostream& operator<< (ostream& out,
const Assignment& assignment){
out<<assignment.m_rowsOfVarArray<<std::endl;
//return the stream. cout print the stream result.
return out;
}
or better yet, avoid all unnecessary friendships by deferring to a public utility method (this also has benefits when your Assignment is a polymorphic base class):
in header file:
namespace biumath
{
class Assignment
{
private:
int **m_varArray;
int m_rowsOfVarArray;
public:
Assignment(); //1
Assignment(char symbol, double value); //2
bool containsValueFor(char symbol) const; //3
double valueOf(char symbol) const; //4
void add(char symbol, double val); //5
void write(std::ostream& os) const; // <=== public helper
};
// free function overload which defers to helper.
// NOTE: it's in the biumath namespace so ADL will find it
inline std::ostream& operator<< (std::ostream& out,
const Assignment& assignment){
assignment.write(out);
return out;
}
}
in CPP file:
namespace biumath {
void Assignment::write(std::ostream& os) const {
os << m_rowsOfVarArray << std::endl;
}
}
You may define the operator in the enclosing namespace (in your case in the global namespace) but you have to use the qualified name.
Thus define the operator like
ostream& biumath::operator<< (ostream& out,
const Assignment& assignment){
out<<assignment.m_rowsOfVarArray<<std::endl;
//return the stream. cout print the stream result.
return out;
}
Only you also have at first to declare the operator in the same namespace where the class is defined.
If you want that the operator would be declared in the global namespace then you can do it the following way
namespace biumath
{
class Assignment;
}
std::ostream& operator<< ( std::ostream &,
const biumath::Assignment & );
namespace biumath
{
class Assignment
{
//...
friend std::ostream& ::operator<< (std::ostream& out,
const Assignment& assignment);
};
}
You've befriended an operator in your biumath namespace, but you don't define that; instead you define a separate operator in the global namespace.
Re-open the namespace in the source file, and put the definition inside it.

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

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;
}
}

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";
}