Templates and overloadering operator << [duplicate] - c++

This question already has answers here:
Overloading friend operator << for template class [duplicate]
(3 answers)
Closed 7 years ago.
I'm trying to overload the << operator for a class template, but the compiler gives me a linker error. The goal is to be able to send a de-referenced base class pointer to std::cout so that the derived operator<< gets called.
Is this possible?
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
private:
T data_;
};
template <typename T>
Derived<T>::Derived(T data)
: IBase(),
data_(data)
{
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt)
{
os << dt.data_;
return os;
}
int _tmain(int argc, _TCHAR* argv[])
{
// Question 1
Derived<int> der(234);
std::cout << der;
// Question 2
//IBase* base = new Derived<int>(5);
// std::cout << *base
}
Here are the errors:
error LNK2001: unresolved external symbol "class
std::basic_ostream > & __cdecl
operator<<(class std::basic_ostream
&,class Derived const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$Derived#H###Z)
and
fatal error LNK1120: 1 unresolved externals

You need to declarate friend operator as a template too
template<typename T1>
friend std::ostream& operator<<(std::ostream& os, const Derived<T1>& dt);

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
declares a non template version friend, so you would have to implement
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
for every T you use:
std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) {
return os << dt.data_;
}
And so on.
A way to do it without duplicate code is with definition inside the class:
template <typename T>
class Derived : public IBase
{
public:
explicit Derived(T data);
friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt)
{
return os << dt.data_;
}
private:
T data_;
};
Demo
An other alternative is to make the function template.
// Forward declarations
template <typename T> class Derived;
template <typename T> std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
And then in Derived, you have 2 choices:
Declare each the template method friend:
template <typename T2>
friend std::ostream& operator<<(std::ostream& os, const Derived<T2>& dt);
So std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) has access to private members of Derived<int>, but also to the ones of Derived<char>
Demo
Declare only the template which matches the argument:
friend std::ostream& operator<< <>(std::ostream& os, const Derived& dt);
and so std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) doesn't have access to private members of Derived<char>.
Demo

replace
friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
with
template<typename D>
friend std::ostream& operator<<(std::ostream& os, const Derived<D>& dt);

Your immediate problem is that the operator needs to be templated.
However, your ultimate goal can't be attained through templates alone as dereferencing a IBase* gets you a IBase& - template instantiation occurs at compile time and the compiler has no access to the runtime type.
So your templated operator will never be used if you pass a dereferenced IBase* to operator <<.
Instead, add a virtual output function to the base and override it:
class IBase
{
public:
IBase() {};
virtual ~IBase() {};
virtual std::ostream& output(std::ostream&) const = 0;
};
template <typename T>
class Derived
: public IBase
{
public:
Derived(T data);
virtual std::ostream& output(std::ostream& os) const
{
os << data;
return os;
}
private:
T data_;
};
std::ostream& operator<<(std::ostream& os, const IBase& dt)
{
return dt.output(os);
}

You don't need to make your friend a template:
friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);
This needs to be changed to:
friend std::ostream& operator<< <>(std::ostream& os, const Derived<T>& dt);
The operator<< function will need to be visible before the friend declaration for this form to work.
You should prefer this form to making the friend a template because you don't need all of the operator's instantiations to be friends, just one of them.

Related

Friend template specialization [duplicate]

I was reading litb's answer to a question here, where he details how to create a specialized friend function of a class template.
I tried to create an exemplar which did just what he suggests (code at the end):
// use '<>' to specialize the function template with the class template's type
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f)
It results in a compiler error:
error: defining explicit specialization ‘operator<< <>’ in friend declaration
Explicitly declaring the template parameter in the specialization doesn't work either:
friend std::ostream& operator<< <T>(std::ostream& os, const foo<T>& f) // same error
On the other hand, changing from using a specialization to use a friend function template instead does work:
template<typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
So my questions are:
what is causing the first error?
how can I explicitly specialize the ostream operator for the surrounding class template specialization?
Exemplar code below:
#include <iostream>
// fwd declarations
template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);
template<typename T>
struct foo
{
foo(T val)
: _val(val)
{}
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f) // error line
//template<typename U>
//friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
{
return os << "val=" << f._val;
}
T _val;
};
int main()
{
foo<std::string> f("hello world");
std::cout << f << std::endl;
exit(0);
}
In litb's example, he's just declaring the specialization as a friend in the class. He's not defining the specialization, which is what your code's doing. You're not allowed to define a specialization in a class declaration (or any non-namespace scope).
What you need is something like:
template <class T>
class foo;
template<class T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
    return os << "val=" << f._val;
}
template<typename T>
struct foo
{
// ...
private:
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);
T _val;
};
You have 2 choices:
Remove fwd declarations and define everything in class.
Example
template <typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
{
return os << "val=" << f._val;
}
Define friend function outside of the class.
Example
template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);
template<typename T>
struct foo
{
foo(T val)
: _val(val)
{}
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);
T _val;
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
return os << "val=" << f._val;
}

c++ template class operator<< overloading [duplicate]

I have read couple of the questions regarding my problem on StackOverflow.com now, and none of it seems to solve my problem. Or I maybe have done it wrong...
The overloaded << works if I make it into an inline function. But how do I make it work in my case?
warning: friend declaration std::ostream& operator<<(std::ostream&, const D<classT>&)' declares a non-template function
warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
/tmp/cc6VTWdv.o:uppgift4.cc:(.text+0x180): undefined reference to operator<<(std::basic_ostream<char, std::char_traits<char> >&, D<int> const&)'
collect2: ld returned 1 exit status
The code:
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const;
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
template <class classT>
ostream& operator<<(ostream &os, const D<classT>& rhs)
{
os << rhs.d;
return os;
}
This is one of those frequently asked questions that have different approaches that are similar but not really the same. The three approaches differ in who you are declaring to be a friend of your function --and then on how you implement it.
The extrovert
Declare all instantiations of the template as friends. This is what you have accepted as answer, and also what most of the other answers propose. In this approach you are needlessly opening your particular instantiation D<T> by declaring friends all operator<< instantiations. That is, std::ostream& operator<<( std::ostream &, const D<int>& ) has access to all internals of D<double>.
template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access all Test<int>, Test<double>... regardless of what T is
}
The introverts
Only declare a particular instantiation of the insertion operator as a friend. D<int> may like the insertion operator when applied to itself, but it does not want anything to do with std::ostream& operator<<( std::ostream&, const D<double>& ).
This can be done in two ways, the simple way being as #Emery Berger proposed, which is inlining the operator --which is also a good idea for other reasons:
template <typename T>
class Test {
friend std::ostream& operator<<( std::ostream& o, const Test& t ) {
// can access the enclosing Test. If T is int, it cannot access Test<double>
}
};
In this first version, you are not creating a templated operator<<, but rather a non-templated function for each instantiation of the Test template. Again, the difference is subtle but this is basically equivalent to manually adding: std::ostream& operator<<( std::ostream&, const Test<int>& ) when you instantiate Test<int>, and another similar overload when you instantiate Test with double, or with any other type.
The third version is more cumbersome. Without inlining the code, and with the use of a template, you can declare a single instantiation of the template a friend of your class, without opening yourself to all other instantiations:
// Forward declare both templates:
template <typename T> class Test;
template <typename T> std::ostream& operator<<( std::ostream&, const Test<T>& );
// Declare the actual templates:
template <typename T>
class Test {
friend std::ostream& operator<< <T>( std::ostream&, const Test<T>& );
};
// Implement the operator
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& t ) {
// Can only access Test<T> for the same T as is instantiating, that is:
// if T is int, this template cannot access Test<double>, Test<char> ...
}
Taking advantage of the extrovert
The subtle difference between this third option and the first is in how much you are opening to other classes. An example of abuse in the extrovert version would be someone that wants to get access into your internals and does this:
namespace hacker {
struct unique {}; // Create a new unique type to avoid breaking ODR
template <>
std::ostream& operator<< <unique>( std::ostream&, const Test<unique>& )
{
// if Test<T> is an extrovert, I can access and modify *any* Test<T>!!!
// if Test<T> is an introvert, then I can only mess up with Test<unique>
// which is just not so much fun...
}
}
You can't declare a friend like that, you need to specify a different template type for it.
template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);
note SclassT so that it doesn't shadow classT. When defining
template <typename SclassT>
ostream& operator<< (ostream & os, const D<SclassT>& rhs)
{
// body..
}
This worked for me without any compiler warnings.
#include <iostream>
using namespace std;
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const {
return (d > rhs.d);
}
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D& rhs) {
os << rhs.d;
return os;
}
private:
classT d;
};
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
I think you shouldn't make friend in the first place.
You can create a public method call print, something like this (for a non template class):
std::ostream& MyClass::print(std::ostream& os) const
{
os << "Private One" << privateOne_ << endl;
os << "Private Two" << privateTwo_ << endl;
os.flush();
return os;
}
and then, outside the class (but in the same namespace)
std::ostream& operator<<(std::ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
I think it should work also for template class, but I haven't tested yet.
Here you go:
#include <cstdlib>
#include <iostream>
using namespace std;
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const { return d > rhs.d;};
classT operator=(const D<classT>& rhs);
template<class classT> friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
template<class classT> ostream& operator<<(ostream& os, class D<typename classT> const& rhs)
{
os << rhs.d;
return os;
}
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}

Explicit specialization of friend function for a class template

I was reading litb's answer to a question here, where he details how to create a specialized friend function of a class template.
I tried to create an exemplar which did just what he suggests (code at the end):
// use '<>' to specialize the function template with the class template's type
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f)
It results in a compiler error:
error: defining explicit specialization ‘operator<< <>’ in friend declaration
Explicitly declaring the template parameter in the specialization doesn't work either:
friend std::ostream& operator<< <T>(std::ostream& os, const foo<T>& f) // same error
On the other hand, changing from using a specialization to use a friend function template instead does work:
template<typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
So my questions are:
what is causing the first error?
how can I explicitly specialize the ostream operator for the surrounding class template specialization?
Exemplar code below:
#include <iostream>
// fwd declarations
template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);
template<typename T>
struct foo
{
foo(T val)
: _val(val)
{}
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f) // error line
//template<typename U>
//friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
{
return os << "val=" << f._val;
}
T _val;
};
int main()
{
foo<std::string> f("hello world");
std::cout << f << std::endl;
exit(0);
}
In litb's example, he's just declaring the specialization as a friend in the class. He's not defining the specialization, which is what your code's doing. You're not allowed to define a specialization in a class declaration (or any non-namespace scope).
What you need is something like:
template <class T>
class foo;
template<class T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
    return os << "val=" << f._val;
}
template<typename T>
struct foo
{
// ...
private:
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);
T _val;
};
You have 2 choices:
Remove fwd declarations and define everything in class.
Example
template <typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
{
return os << "val=" << f._val;
}
Define friend function outside of the class.
Example
template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);
template<typename T>
struct foo
{
foo(T val)
: _val(val)
{}
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);
T _val;
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
return os << "val=" << f._val;
}

operator<< overloading to call a print function trouble

Okay I'm a little stuck on trying to overload the << operator for my template class. The requirement is that the << operator must call a void print function defined for this class.
Here is the important stuff from the template header:
template <class T>
class MyTemp {
public:
MyTemp(); //constructor
friend std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a);
void print(std::ostream& os, char ofc = ' ') const;
and here is my print function basically it's a vector and prints last element to first:
template <class T>
void Stack<T>::print(std::ostream& os, char ofc = ' ') const
{
for ( int i = (fixstack.size()-1); i >= 0 ; --i)
{
os << fixstack[i] << ofc;
}
}
and here is how I have the operator<< overloaded:
template <class T>
std::ostream& operator<< (std::ostream& os, const Stack<T>& a)
{
// So here I need to call the a.print() function
}
But I am receiving an "unresolved external symbol" error. So really I guess I have two issues. The first, is the way to fix the error above. Second, once that is fixed would I just call a.print(os) inside << overload? I know it needs to return an ostream though. Any help would be greatly appreciated!
The simplest thing to do would be to leave print public (as it is in your example), so the operator doesn't need to be a friend.
template <class T>
class MyTemp {
public:
void print(std::ostream& os, char ofc = ' ') const;
};
template <class T>
std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
If you do need it to be private, then you need to declare the correct template specialisation to be a friend - your friend declaration declares a non-template operator in the surrounding namespace, not a template. Unfortunately, to make a template a friend you need to declare it beforehand:
// Declare the templates first
template <class T> class MyTemp;
template <class T> std::ostream& operator<< (std::ostream&, const MyTemp<T>&);
template <class T>
class MyTemp {
public:
friend std::ostream& operator<< <>(std::ostream& os, const MyTemp<T>& a);
// With a template thingy here ^^
private:
void print(std::ostream& os, char ofc = ' ') const;
};
template <class T>
std::ostream& operator<< (std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
Or you could define the operator inline:
template <class T>
class MyTemp {
public:
friend std::ostream& operator<<(std::ostream& os, const MyTemp<T>& a) {
a.print(os);
return os;
}
private:
void print(std::ostream& os, char ofc = ' ') const;
};
For your last question:
Second, once that is fixed would I just call a.print(os) inside << overload? I know it needs to return an ostream though.
It does indeed need to return an ostream - so just return the one that was passed in, as in my example code.
This error means there is an symbol which could not be recognized by the linker.on what variable are u getting this error
and also please check on stack as well because there is a std::stack class available.
As your print member function is public, there's no need to declare operator<< as friend.
Beware that you are using class Stack is your overload, and MyTemp above ...

overloading friend operator<< for template class

I have read couple of the questions regarding my problem on StackOverflow.com now, and none of it seems to solve my problem. Or I maybe have done it wrong...
The overloaded << works if I make it into an inline function. But how do I make it work in my case?
warning: friend declaration std::ostream& operator<<(std::ostream&, const D<classT>&)' declares a non-template function
warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
/tmp/cc6VTWdv.o:uppgift4.cc:(.text+0x180): undefined reference to operator<<(std::basic_ostream<char, std::char_traits<char> >&, D<int> const&)'
collect2: ld returned 1 exit status
The code:
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const;
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
template <class classT>
ostream& operator<<(ostream &os, const D<classT>& rhs)
{
os << rhs.d;
return os;
}
This is one of those frequently asked questions that have different approaches that are similar but not really the same. The three approaches differ in who you are declaring to be a friend of your function --and then on how you implement it.
The extrovert
Declare all instantiations of the template as friends. This is what you have accepted as answer, and also what most of the other answers propose. In this approach you are needlessly opening your particular instantiation D<T> by declaring friends all operator<< instantiations. That is, std::ostream& operator<<( std::ostream &, const D<int>& ) has access to all internals of D<double>.
template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access all Test<int>, Test<double>... regardless of what T is
}
The introverts
Only declare a particular instantiation of the insertion operator as a friend. D<int> may like the insertion operator when applied to itself, but it does not want anything to do with std::ostream& operator<<( std::ostream&, const D<double>& ).
This can be done in two ways, the simple way being as #Emery Berger proposed, which is inlining the operator --which is also a good idea for other reasons:
template <typename T>
class Test {
friend std::ostream& operator<<( std::ostream& o, const Test& t ) {
// can access the enclosing Test. If T is int, it cannot access Test<double>
}
};
In this first version, you are not creating a templated operator<<, but rather a non-templated function for each instantiation of the Test template. Again, the difference is subtle but this is basically equivalent to manually adding: std::ostream& operator<<( std::ostream&, const Test<int>& ) when you instantiate Test<int>, and another similar overload when you instantiate Test with double, or with any other type.
The third version is more cumbersome. Without inlining the code, and with the use of a template, you can declare a single instantiation of the template a friend of your class, without opening yourself to all other instantiations:
// Forward declare both templates:
template <typename T> class Test;
template <typename T> std::ostream& operator<<( std::ostream&, const Test<T>& );
// Declare the actual templates:
template <typename T>
class Test {
friend std::ostream& operator<< <T>( std::ostream&, const Test<T>& );
};
// Implement the operator
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& t ) {
// Can only access Test<T> for the same T as is instantiating, that is:
// if T is int, this template cannot access Test<double>, Test<char> ...
}
Taking advantage of the extrovert
The subtle difference between this third option and the first is in how much you are opening to other classes. An example of abuse in the extrovert version would be someone that wants to get access into your internals and does this:
namespace hacker {
struct unique {}; // Create a new unique type to avoid breaking ODR
template <>
std::ostream& operator<< <unique>( std::ostream&, const Test<unique>& )
{
// if Test<T> is an extrovert, I can access and modify *any* Test<T>!!!
// if Test<T> is an introvert, then I can only mess up with Test<unique>
// which is just not so much fun...
}
}
You can't declare a friend like that, you need to specify a different template type for it.
template <typename SclassT>
friend ostream& operator<< (ostream & os, const D<SclassT>& rhs);
note SclassT so that it doesn't shadow classT. When defining
template <typename SclassT>
ostream& operator<< (ostream & os, const D<SclassT>& rhs)
{
// body..
}
This worked for me without any compiler warnings.
#include <iostream>
using namespace std;
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const {
return (d > rhs.d);
}
classT operator=(const D<classT>& rhs);
friend ostream& operator<< (ostream & os, const D& rhs) {
os << rhs.d;
return os;
}
private:
classT d;
};
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}
I think you shouldn't make friend in the first place.
You can create a public method call print, something like this (for a non template class):
std::ostream& MyClass::print(std::ostream& os) const
{
os << "Private One" << privateOne_ << endl;
os << "Private Two" << privateTwo_ << endl;
os.flush();
return os;
}
and then, outside the class (but in the same namespace)
std::ostream& operator<<(std::ostream& os, const MyClass& myClass)
{
return myClass.print(os);
}
I think it should work also for template class, but I haven't tested yet.
Here you go:
#include <cstdlib>
#include <iostream>
using namespace std;
template <class T>
T my_max(T a, T b)
{
if(a > b)
return a;
else
return b;
}
template <class classT>
class D
{
public:
D(classT in)
: d(in) {};
bool operator>(const D& rhs) const { return d > rhs.d;};
classT operator=(const D<classT>& rhs);
template<class classT> friend ostream& operator<< (ostream & os, const D<classT>& rhs);
private:
classT d;
};
template<class classT> ostream& operator<<(ostream& os, class D<typename classT> const& rhs)
{
os << rhs.d;
return os;
}
int main()
{
int i1 = 1;
int i2 = 2;
D<int> d1(i1);
D<int> d2(i2);
cout << my_max(d1,d2) << endl;
return 0;
}