Overloading << and >> as outside member functions for template class [duplicate] - c++

This question already has answers here:
overloading friend operator<< for template class
(5 answers)
Closed 1 year ago.
I am trying to define my operator overloading outside the class like this:
template <typename Type>
class myClass
{
...
friend std::ostream& operator << (std::ostream&, const myClass&);
friend std::istream& operator >> (std::istream&, myClass&);
...
}
template <typename Type>
std::ostream& myClass<Type> :: operator << (std::ostream& out, const myClass<Type>& other) { ... }
template <typename Type>
std::istream& myClass<Type> :: operator >> (std::istream& in, myClass<Type>& other) { ... }
My problem is that I get an error saying something like "class template class has no member operator<<" and I do not understand how or why is this happening.

For starters the friend functions are not member functions of the class where they are declared.
So these declarations in any case are incorrect.
template <typename Type>
std::ostream& myClass<Type> :: operator << (std::ostream& out, const myClass<Type>& other) { ... }
template <typename Type>
std::istream& myClass<Type> :: operator >> (std::istream& in, myClass<Type>& other) { ... }
Secondly within the class definition you declared non-template friend functions.
Either you need to provide their definitions within the class definition. Or for each potential template argument of the class you have to define the friend functions outside the class.
Here is a demonstration program that shows how to define a non-template friend function within the class template definition.
#include <iostream>
template <typename T>
class A
{
private:
T t;
public:
A( const T &t ) : t( t ) {}
friend std::ostream &operator <<( std::ostream &os, const A &a )
{
return os << a.t;
}
};
int main()
{
std::cout << A<int>( 10 ) << '\n';
std::cout << A<const char *>( "Hello" ) << '\n';
}
The program output is
10
Hello
And here is a demonstration program that shows how to define the friend functions outside the class template definition. That is for each used specialization of the class template you need to define the non-template friend functions.
#include <iostream>
template <typename T>
class A
{
private:
T t;
public:
A( const T &t ) : t( t ) {}
friend std::ostream &operator <<( std::ostream &os, const A &a );
};
std::ostream &operator <<( std::ostream &os, const A<int> &a )
{
return os << a.t;
}
std::ostream &operator <<( std::ostream &os, const A<const char *> &a )
{
return os << a.t;
}
int main()
{
std::cout << A<int>( 10 ) << '\n';
std::cout << A<const char *>( "Hello" ) << '\n';
}
An alternative approach is to declare template friend functions. For example
#include <iostream>
template <typename T>
class A
{
private:
T t;
public:
A( const T &t ) : t( t ) {}
template <typename T>
friend std::ostream &operator <<( std::ostream &os, const A<T> &a );
};
template <typename T>
std::ostream &operator <<( std::ostream &os, const A<T> &a )
{
return os << a.t;
}
int main()
{
std::cout << A<int>( 10 ) << '\n';
std::cout << A<const char *>( "Hello" ) << '\n';
}

Related

How to override output operator (<<) as a function template outside a class template

I am reading Section 2.4 of the book "C++ tempalte, a complete guide".
I tried to override output operator (<<) as a function template outside the class template Stack<>.
Below is my code, but it doesn't work.
#include <iostream>
#include <string>
#include <vector>
template<class T>
class Stack
{
private:
std::vector<T> v;
public:
void push(T a);
void printOn(std::ostream & os) const;
template <typename U>
friend std::ostream& operator<< (std::ostream& out, const Stack<U> & s);
};
template<typename T>
std::ostream& operator<< (std::ostream out, const Stack<T> & s)
{
s.printOn(out);
return out;
}
template<class T>
void Stack<T>::push(T a)
{
v.push_back(a);
}
template<class T>
void Stack<T>::printOn(std::ostream & out) const
{
for(T const & vi : v)
{out << vi << " ";}
}
int main()
{
Stack<int> s1;
s1.push(12);
s1.push(34);
std::cout << s1;
}
You are just omitting the &, which makes the operator<< inside and outside the class have different function signatures, they are both valid for std::cout << s1, hence the ambiguity
template<typename T>
std::ostream& operator<< (std::ostream& out, const Stack<T> & s)
// ^
{
s.printOn(out);
return out;
}

Friend template operator

The following program does not compile in MS Visual Studio 19.
#include <iostream>
#include <string>
template <typename T>
class A;
template <typename T>
std::ostream &operator <<( std::ostream &, const A<T> & );
template <typename T>
class A
{
private:
T x;
public:
A( const T &x ) : x( x ) {}
friend std::ostream &::operator <<( std::ostream &, const A<T> & );
};
template <typename T>
std::ostream &operator <<( std::ostream &os, const A<T> &a )
{
return os << "a.x = " << a.x;
}
int main()
{
std::cout << A<std::string>( "Hello" ) << '\n';
}
The compiler says that operator << is not a function.
While the following program
#include <iostream>
#include <string>
template <typename T>
class A;
template <typename T>
std::ostream &f( std::ostream &, const A<T> & );
template <typename T>
class A
{
private:
T x;
public:
A( const T &x ) : x( x ) {}
friend std::ostream &::f( std::ostream &, const A<T> & );
};
template <typename T>
std::ostream &f( std::ostream &os, const A<T> &a )
{
return os << "a.x = " << a.x;
}
int main()
{
f( std::cout, A<std::string>( "Hello" ) ) << '\n';
}
compiles successfully.
What is the reason of that the first program does not compile? Is it a bug of MS Visual Studio 19 or do I have missed something from the C++ 20 Standard?
According to the C++ 20 Standard (13.7.4 Friends)
(1.3) — if the name of the friend is a qualified-id and a matching
function template is found in the specified class or namespace, the
friend declaration refers to the deduced specialization of that
function template (13.10.2.6), otherwise,
Your program is defective; however there is indeed a bug (or two) in Visual Studio.
First, your friend declaration should be spelled with a <> to indicate that it is a template specialization that is the friend:
friend std::ostream &::operator <<<>( std::ostream &, const A<T> & );
// ^~
It is also acceptable to spell it with T explicitly (i.e. not inferring the template arguments):
friend std::ostream &::operator <<<T>( std::ostream &, const A<T> & );
// ^~~
Incidentally, gcc provides a helpful hint to make this change.
However MSVC will still erroneously reject the program; this appears to only happen templates of the specific operator<< where the class template argument is passed by reference, but not by value:
#include <iostream>
template<class> struct A;
template<class> struct B;
template<class T> std::ostream& f(std::ostream&, A<T>);
template<class T> std::ostream &operator<<(std::ostream&, A<T>);
template<class T> std::ostream& f(std::ostream&, B<T> const&);
template<class T> std::ostream &operator<<(std::ostream&, B<T> const&);
template<class T> struct A {
friend std::ostream& ::f<T>(std::ostream&, A<T>);
friend std::ostream& ::operator<<<T>(std::ostream&, A<T>);
};
template<class T> struct B {
friend std::ostream& ::f<T>(std::ostream&, B<T> const&);
friend std::ostream& ::operator<<<T>(std::ostream&, B<T> const&); // MSVC bug
};
template<class T> std::ostream& f(std::ostream& os, A<T>) { return os << "1"; }
template<class T> std::ostream& operator<<(std::ostream& os, A<T>) { return os << "2"; }
template<class T> std::ostream& f(std::ostream& os, B<T> const&) { return os << "3"; }
template<class T> std::ostream& operator<<(std::ostream& os, B<T> const&) { return os << "4"; }
int main() {
f(std::cout, A<int>()) << ' ' << A<int>() << '\n';
f(std::cout, B<int>()) << ' ' << B<int>() << '\n';
}
The fact that MSVC rejects only friend std::ostream& ::operator<<<T>(std::ostream&, B<T> const&) makes it clear that this is a compiler bug. gcc and clang accept and print 1 2\n3 4, as expected.
Another, similar defect in MSVC is that it will reject friend std::ostream& ::f<>(std::ostream&, A) (that is, using the injected-class-name to name A<T>).
Regarding the Standard, the language was changed substantially post-C++20 by P1787R6: Declarations and where to find them; in particular, it removes the language that you quote in your question. As such, I don't think you can use that as an argument for being allowed to omit the <> from the friend function template specialization declaration, since P1787R6 resolves a bunch of CWG DRs and so can be regarded as a post-publication correction.

How to overload ostream for a member struct of a templated class

I'm implementing a dictionary in C++ using a binary tree, each node in my tree has a key(int), item(string) and left and right child.
During this implementation, I overloaded the ostream operator for my BinaryTree class to print out the contents of the tree.
Additionally, I overloaded the ostream to work with Node pointers that would then print out the key and the item of that node.
This worked fine. However when I tried to then make the tree a template to work with any type for my key or item overloading these operators became more difficult.
I isolated the problem to make it easier to work on, additionally, I have tried playing around with both a node and a node pointer to see if I can get one to work without the other.
Here is the class I have made to test the problem, this class is not templated and works fine.
test.h
class myClass
{
public:
using Key = int;
myClass(Key);
friend std::ostream & operator<<(std::ostream &, const myClass &);
private:
struct Thing {
Key data;
Thing();
Thing(Key);
};
Thing* B;
Thing A;
void disp(std::ostream &) const;
friend std::ostream & operator<<(std::ostream &, myClass::Thing);
friend std::ostream & operator<<(std::ostream &, myClass::Thing *);
};
test.cpp
myClass::Thing::Thing(Key Num) { data = Num; }
myClass::myClass(Key Num)
{
A = Thing(Num); B = &A;
}
void myClass::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
std::ostream & operator<<(std::ostream & os, const myClass & c)
{
c.disp(os); return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing th)
{
os << th.data; return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing *th)
{
os << th->data; return os;
}
With this class, I can easily make an instance of my class and std::cout it giving the output as expected.
Then turning this class into a template:
template <class T> class myTemplate
{
public:
using Key = T;
myTemplate(Key);
template<class A>
friend std::ostream & operator<<(std::ostream &, const myTemplate<A> &);
private:
struct Thing;
Thing A;
Thing* B;
void disp(std::ostream &) const;
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing);
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing *);
};
template <class T> struct myTemplate<T>::Thing
{
T data;
Thing() = default;
Thing(Key);
};
//Create new thing A with B a pointer to A
template <class T> myTemplate<T>::myTemplate(Key Num)
{
A = Thing(Num);
B = &A;
}
//Displays Node A & B
template <class T> void myTemplate<T>::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
template <class T> myTemplate<T>::Thing::Thing(Key Num)
{
data = Num;
}
//Overloading << will call disp function, in turn print A & B to stream
template<class T> std::ostream & operator<<(std::ostream & os, const myTemplate<T> & c)
{
c.disp(os); return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing th)
{
os << th.data; return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing *th)
{
os << th->data; return os;
}
However with myTemplate when I tried in the main():
myTemplate Template(5);
cout << Template;
The code will not compile as I get the error:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const myTemplate<std::string>::Thing' (or there is no acceptable conversion)
Additionally commenting out the line:
os << A << std::endl;
So only B is being outputted to the stream, the code will compile. However the data of B is not outputted, only the memory address of B.
I have noticed that using breakpoints when trying to output B the code does not even use the overload function I defined. This is not the case for the non-templated class as the overloads I defined are used for both A and B.
So what is the correct way to overload the ostream operator to work for the struct member?
Apologises for the long winded question, felt I should include what I had determined myself.
Since template implementation is going to be in a single translate unit(header file) itself, you are not going to gain anything more, by tearing the things apart. Therefore, keep the definitions and non-member functions inside the class itself, which will provide you with much clear code and also improve the readability of the template class:
See this
#include <iostream>
template <class T> class myTemplate
{
public:
using Key = T;
private:
struct Thing
{
T data;
Thing() = default;
Thing(Key Num) : data(Num) {}
};
Thing A;
Thing* B = nullptr;
public:
myTemplate(Key Num) : A(Thing(Num)), B(&A) {}
friend std::ostream & operator<<(std::ostream& out, const myTemplate &obj)
{
return out << obj.A << std::endl << obj.B << std::endl;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing thing)
{
return out << thing.data;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing *thing)
{
return out << thing->data;
}
};
int main()
{
myTemplate<int> obj(10);
std::cout << obj;
return 0;
}
Update: If the final aim of providing that two operator<< overloads to the struct Thing is just to conveniently call in the operator<< of the myTemplate class, then you do not need that, rather simply print the data directly in operator<< of the myTemplate class. That will again reduce significate amount of codes(if that is the case!).
Nevertheless, now you can provide a specialization for the non-member(friend) function(i.e, operator<<) for the myTemplate class, as follows:
template <class T> class myTemplate; // forward declaration
template <class T> std::ostream& operator<<(std::ostream& out, const myTemplate<T> &obj);
template <class T> class myTemplate
{
private:
using Key = T;
private:
template <class Type = T> struct Thing
{
Type data;
Thing() = default;
Thing(const Key Num) : data(Num) {}
};
private:
Thing<> A;
Thing<> *B = nullptr;
public:
myTemplate(const Key Num) : A(Thing<>(Num)), B(&A) {}
friend std::ostream & operator<<<>(std::ostream& out, const myTemplate &obj);
};
template <class T> std::ostream & operator<<(std::ostream& out, const myTemplate<T> &obj)
{
return out << obj.A.data << std::endl << obj.B->data << std::endl;
}

Use of overloaded operator ambiguous

The following code:
typedef void HELPER;
const HELPER* helper = _helper;
inline ostream& operator <<(ostream& out, const HELPER* arg)
{ out << (const char*)(arg); return out; }
Blows up if I attempt a
cout << helper;
Specifically, I get:
main.cpp:35:28: error: use of overloaded operator '<<' is ambiguous
(with operand types 'basic_ostream >' and 'const HELPER *' (aka 'const void *'))
and it lists a few candidates:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:207:0: note: candidate function
basic_ostream& operator<<(const void* __p);
^
main.cpp:25:17: note: candidate function
inline ostream& operator <<(ostream& out, const HELPER* arg)
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/ostream:195:20: note: candidate function
basic_ostream& operator<<(bool __n);
^
I'm a little surprised that my typedef isn't invoking a stronger type matching here. How can I get this operator overload running?
EDIT: Further clarification, the purpose of this code is that I am dual-targeting a set of Arduino libraries. They manage their strings frequently with:
typedef void __FlashStringHelper;
void showHelp(const __FlashStringHelper* helpText)
{
Serial.print(helpText);
}
I like iostream and planned on this dual target, so I overloaded << on Serial object and made the previous into (this is the oversimplified version, for example)
#define cout Serial
void showHelp(const __FlashStringHelper* helpText)
{
cout << helpText;
}
Now I want to actually target real iostream for a different arch, but the old Arduino code can't vary (much) from its __FlashStringHelpers. That's where I'm at
typedef doesn't create types it aliases them,
inline ostream& operator <<(ostream& out, const HELPER* arg)
is equivalent to
inline ostream& operator <<(ostream& out, const void* arg)
Maybe you wanted to create a type named HELPER
class HELPER{};
As Zekian answered your question this here is something that may be of use to you or help you to achieve what you are trying to do.
#include <iostream>
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
int main() {
Helper<int> helper( 3 );
std::cout << helper << std::endl;
return 0;
}
It is a wrapper class template with an overloaded ostream operator<<. This will work for integral and atomic types. If you pass another struct or class object then you will have to define other overloaded ostream operators for them.
Example - Same Class Template, but this time using a class or struct.
#include <iostream>
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
struct Staff {
int employees = 4; // Default to 4
};
int main() {
Staff staff;
Helper<Staff> helper( staff );
std::cout << helper << std::endl; // will not compile
return 0;
}
To fix this ostream will need an overloaded operator for Staff object
template <class T>
class Helper {
private:
T obj_;
public:
explicit Helper<T>( T obj ) : obj_(obj) {}
public:
T getObj() const { return obj_; }
void setObj( T obj ) { obj_ = obj; }
template<class U>
inline friend std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs );
};
template<class U>
std::ostream& operator<< ( std::ostream& out, const Helper<U>& rhs ) {
return out << rhs.obj_;
}
struct Staff {
int employees = 4;
inline friend std::ostream& operator<< ( std::ostream& out, const Staff& rhs );
};
std::ostream& operator<<( std::ostream& out, const Staff& rhs ) {
return out << rhs.employees;
}
int main() {
Staff staff;
Helper<Staff> helper( staff ); // Default to 4
std::cout << helper << std::endl; // Will Print 4
// To Change Staff's Employee count for the helper wrapper do this:
staff.employees = 12; // Change To 12
helper.setObj( staff ); // pass the changed struct back into helper
std::cout << helper3 << std::endl; // Will Now Print 12
// And For Other Default Types
Helper<int> helper2( 3 );
std::cout << helper2 << std::endl;
Helper<float> helper3( 2.4f );
std::cout << helper3 << std::endl;
return 0;
}

<< operator overloading for template class object

I have written a C++ STL like bitset class:
template<size_t N>
class bitset {
public:
...........
friend std::ostream& operator << (std::ostream &, bitset<N> const&);
private:
..........
};
// end of class
template<size_t N>
std::ostream& operator << (std::ostream &os, bitset<N> const& rhs) {
............
.........
return os;
}
And I am trying to use it like this:
bitset<5> foo; // success
std::cout << foo << std::endl; // fail
And the error message is -
undefined reference to `operator<<(std::ostream&, bitSet<5u> const&)
What's the problem actually?
Your friend's declaration must be a template as well, just like the definition is:
template <size_t N>
class bitset {
public:
template <size_t M>
friend std::ostream& operator << (std::ostream &, bitset<M> const&);
};
template <size_t M>
std::ostream& operator << (std::ostream &os, bitset<M> const& rhs) {
return os;
}
Alternatively, you could declare the operator<< directly within the class scope:
template<size_t N>
class bitset {
public:
friend std::ostream& operator << (std::ostream & os, bitset const&) {
return os;
}
};
Some possible answers to your question are given here.
In addition to the answer of Piotr S., you can also predeclare the function templates:
template<size_t N> class bitset;
template<size_t N> std::ostream& operator << (std::ostream &, bitset<N> const&);
//now comes your class definition