Redefinition error in ostream overload in template and inherited classes - c++

I am trying to overload the ostream operator in template and inherited classes and I have been following some tips here and here, but I get a redefinition error. Here is a reproduction of my code:
#include <iostream>
enum type
{
A,
B
};
template <type T>
class base
{
protected:
virtual std::ostream& print(std::ostream& out) const =0;
};
template <type T>
class derived: public base<T>
{
protected:
virtual std::ostream& print(std::ostream& out) const
{
out<<"Hello World.\n";
return out;
}
public:
template <type S>
friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
{
return (D.print(out));
}
};
int main ()
{
#ifdef __NOT_WORKING__
derived<A> a;
std::cout<<a;
derived<B> b;
std::cout<<b;
#else
derived<A> a;
std::cout<<a;
#endif
return 0;
}
If I define just a derived A class, everything works, but if I define a derived A and a derived B class I get this error from the compiler:
test.cpp: In instantiation of 'class derived<(type)1u>':
test.cpp:38:20: required from here
test.cpp:27:30: error: redefinition of 'template<type S> std::ostream& operator<<(std::ostream&, const derived<S>&)'
friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
^
test.cpp:27:30: note: 'template<type S> std::ostream& operator<<(std::ostream&, const derived<S>&)' previously defined here
test.cpp: In instantiation of 'std::ostream& operator<<(std::ostream&, const derived<S>&) [with type S = (type)1u; type T = (type)0u; std::ostream = std::basic_ostream<char>]':
test.cpp:39:20: required from here
test.cpp:20:31: error: 'std::ostream& derived<T>::print(std::ostream&) const [with type T = (type)1u; std::ostream = std::basic_ostream<char>]' is protected
virtual std::ostream& print(std::ostream& out) const
^
test.cpp:29:37: error: within this context
return (D.print(out));
^
Why is it redefining the friend function?
Thanks for your time.
PS. I am using gcc49.

Replace
template <type S>
friend std::ostream& operator<<(std::ostream& out, const derived<S>& D)
{
return (D.print(out));
}
with
friend std::ostream& operator<<(std::ostream& out, const derived<T>& D)
{
return (D.print(out));
}
error will go away.
With earlier definition, you are trying to define a new template function with same signature.

[temp.friend]/4:
When a function is defined in a friend function declaration in a class
template, the function is instantiated when the function is odr-used.
The same restrictions on multiple declarations and definitions that
apply to non-template function declarations and definitions also apply
to these implicit definitions.
Clang compiles the above fine - that can be considered a bug, but recall that violations of the ODR are ill-formed with no diagnostic required.
You have two ways to solve this. Extract the definition of the template:
template <typename T>
class derived: public base<T>
{
// [..]
template <type S>
friend std::ostream& operator<<(std::ostream& out, const derived<S>& D);
};
template <type S>
std::ostream& operator<<(std::ostream& out, const derived<S>& D)
{
return (D.print(out));
}
Or make the operator a non-template:
template <type T>
class derived: public base<T>
{
// [..]
friend std::ostream& operator<<(std::ostream& out, const derived<T>& D)
{
return (D.print(out));
}
};

Related

friend operator<< of a template class, with additional default template parameter

In the following code, A is a template class, depending on a non-type bool type parameter. A friend operator<< is defined for both A<true> and A<false>. The operator<< additionally depends on another bool template parameter.
#include <ostream>
#include <iostream>
#include <type_traits>
template <bool type>
class A;
template <>
class A<true> {
int m_x;
public:
A(int x) : m_x{x} { }
template <bool d, bool type>
friend std::ostream& operator<<(std::ostream& os, const A<type>& a);
};
template <>
class A<false> {
int m_y;
public:
A(int y) : m_y{y} { }
template <bool d, bool type>
friend std::ostream& operator<<(std::ostream& os, const A<type>& a);
};
template <bool d, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a)
{
if constexpr (type) {
os << "m_x = " << a.m_x << std::endl;
if constexpr (d) { os << "2m_x = " << a.m_x << std::endl; }
}
else {
os << "m_y = " << a.m_y << std::endl;
if constexpr (d) { os << "2m_y = " << a.m_y << std::endl; }
}
return os;
}
int main()
{
A<true> atrue{2};
A<false> afalse{3};
operator<< <true>(std::cout, atrue);
operator<< <false>(std::cout, atrue);
operator<< <true>(std::cout, afalse);
operator<< <false>(std::cout, afalse);
return 0;
}
See it live on Coliru.
Now, I would like to give a default value of the template parameter d of operator<<, say d=false such that this statement
std::cout << atrue;
is equivalent to
operator<< <false>(std::cout, atrue);
because bool d takes a default value d=false and bool type is deduced from the second argument of operator<<.
Is there a syntax to allow for that?
If I insert the default parameter in the friend declaration
template <bool d = false, bool type>
friend std::ostream& operator<<(std::ostream& os, const A<type>& a);
I get a compile error:
main.cpp:14:71: error: default template arguments may not be used in
template friend declarations
If I insert the default parameter in the code of operator<<
template <bool d = false, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a)
{
...
again it does not compile giving error
main.cpp:27:15: error: redeclaration of friend 'template std::ostream& operator<<(std::ostream&, const A&)' may not
have default template arguments
27 | std::ostream& operator<<(std::ostream& os, const A& a)
main.cpp:14:26: note: 'template std::ostream&
operator<<(std::ostream&, const A&)' previously declared here
14 | friend std::ostream& operator<<(std::ostream& os, const
A& a);
OK, actually the solution was relatively easy. It is enough to add a declaration of the template operator<< before the class specializations:
template <bool type>
class A;
template <bool d = false, bool type>
std::ostream& operator<<(std::ostream& os, const A<type>& a);
....
In this way the friend declaration inside A<type> does not declare operator<< in first place, but only declares that it is a friend.
A working example can be checked here.

How to properly overload the insertion operator for a templated class that's part of a user-defined namespace?

I checked the answers to this question: Overloading operator<< for a templated class, but unfortunately nothing is working for me so far. Meaning, the compiler is constantly throwing myriad errors at me.
#include <iostream>
namespace usr {
// Forward declarations
template <typename T> class A;
template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>&);
template <typename T>
class A {
public:
friend std::ostream& operator<<(std::ostream& os,
const usr::A<T>& a);
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>& a) {
os << "test";
return os;
}
}
int main() {
usr::A<int> a;
std::cout << a << std::endl;
return 0;
}
The error I get:
$ g++ -std=c++11 test.cpp && ./a.out
test.cpp:15:67: warning: friend declaration ‘std::ostream& usr::operator<<(std::ostream&, const usr::A<T>&)’ declares a non-template function [-Wnon-template-friend]
const usr::A<T>& a);
^
test.cpp:15:67: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
/tmp/ccklebu2.o: In function `main':
test.cpp:(.text+0x24): undefined reference to `usr::operator<<(std::ostream&, usr::A<int> const&)'
collect2: error: ld returned 1 exit status
The following version doesn't not work either:
#include <iostream>
namespace usr {
template <typename T>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << "test";
return os;
}
};
}
int main() {
usr::A<int> a;
std::cout << a << std::endl;
return 0;
}
Here's the error I get plus a whole lot more which I'm not going to include here:
test2.cpp:8:55: error: invalid use of template-name ‘usr::A’ without an argument list
const usr::A& a) {
You need to take ostream in your function by reference. Also, when you declare a friend you need to include the template argument: friend std::ostream& operator<< <T>. Here's your first version modified that works for me:
#include <iostream>
namespace usr {
// Forward declarations
template <typename T> class A;
template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>&);
// Class
template <typename T>
class A {
public:
friend std::ostream& operator<< <T>(std::ostream& os, const usr::A<T>& a);
};
// Friend function
template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>& a) {
os << "test";
return os;
}
}
int main() {
usr::A<int> a;
std::cout << a << std::endl;
return 0;
}
The first answer to your referred to question would seem to answer this.
In the first case, you need the friend delcaration to declare a friend template rather than non-template overloaded functions:
friend std::ostream& operator<< <>(std::ostream &os, const usr::A<T>& a);
note the extra <> that designates this as a firend template.
In the second case, you need to prived the template argument to the friend function:
friend std::ostream& operator<<(std::ostream &os, const usr::A<T>& a) {
note the extra <T>, the type parameter to A

operator<<(ostream&, const BigUnsigned<I>&) must take exactly one argument

I tried to separate the declaration and definition of my templated member function of a templated class, but ended up with the following error and warning.
template <typename I>
class BigUnsigned{
const size_t cell_size=sizeof(I);
std::vector<I> _integers;
public:
BigUnsigned();
BigUnsigned(I);
friend std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu);
};
std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu){
for (auto integer : bu._integers){
out<<integer<<std::endl;
}
return out;
}
../hw06/bigunsigned.h:13:77: warning: friend declaration
'std::ostream& operator<<(std::ostream&, const BigUnsigned&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu);
^ ../hw06/bigunsigned.h:13:77: note: (if this is not what you
intended, make sure the function template has already been declared
and add <> after the function name here) ../hw06/bigunsigned.h:16:51:
error: invalid use of template-name 'BigUnsigned' without an argument
list std::ostream& operator<<(std::ostream& out, const BigUnsigned&
bu){
^ ../hw06/bigunsigned.h: In function 'std::ostream&
operator<<(std::ostream&, const int&)': ../hw06/bigunsigned.h:17:28:
error: request for member '_integers' in 'bu', which is of non-class
type 'const int'
for (auto integer : bu._integers){
^
When I joined the declaration and definition like this, everything compiles fine.
template <typename I>
class BigUnsigned{
const size_t cell_size=sizeof(I);
std::vector<I> _integers;
public:
BigUnsigned();
BigUnsigned(I);
friend std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu){
for (auto integer : bu._integers){
out<<integer<<std::endl;
}
return out;
}
};
The purpose was to print member variable _integers to cout. What might be the problem?
P.S.: Using this question I made the function free, but did not help.
BigUnsigned is a template type so
std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu)
Will not work as there is no BigUnsigned. You need to make the friend function a template so you can take different types of BigUnsigned<some_type>s.
template <typename I>
class BigUnsigned{
const size_t cell_size=sizeof(I);
std::vector<I> _integers;
public:
BigUnsigned();
BigUnsigned(I);
template<typename T>
friend std::ostream& operator<<(std::ostream& out, const BigUnsigned<T>& bu);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, const BigUnsigned<T>& bu){
for (auto integer : bu._integers){
out<<integer<<std::endl;
}
return out;
}
The reason the second example works is that since it is declared inside the class it uses the template type that the class uses.
A refinement to the answer by NathanOliver.
With the other answer, all instantiations of the function template are friends of all instatiations of the class template.
operator<< <int> is a friend of BigUnsigned<int> as well as BigUnsigned<double>.
operator<< <double> is a friend of BigUnsigned<double> as well as BigUnsigned<FooBar>.
You can change the declarations a little bit so that
operator<< <int> is a friend of BigUnsigned<int> but not of BigUnsigned<double>.
operator<< <double> is a friend of BigUnsigned<double> but not BigUnsigned<FooBar>.
// Forward declaration of the class template.
template <typename I> class BigUnsigned;
// Forward declaration of the function template
template <typename I>
std::ostream& operator<<(std::ostream& out, const BigUnsigned<I>& bu);
// Change the friend-ship declaration in the class template.
template <typename I>
class BigUnsigned{
const size_t cell_size=sizeof(I);
std::vector<I> _integers;
public:
BigUnsigned();
BigUnsigned(I);
// Grant friend-ship only to a specific instantiation of the
// function template.
friend std::ostream& operator<< <I>(std::ostream& out, const BigUnsigned<I>& bu);
};
To add a third variant that improves the readability a little bit, is to define the friend function inside the class:
#include <iostream>
template <typename T>
class Foo {
int test = 42;
// Note: 'Foo' inside the class body is basically a shortcut for 'Foo<T>'
// Below line is identical to: friend std::ostream& operator<< (std::ostream &os, Foo<T> const &foo)
friend std::ostream& operator<< (std::ostream &os, Foo const &foo) {
return os << foo.test;
}
};
int main () {
Foo<int> foo;
std::cout << foo << '\n';
}

Friend operator in template struct raises redefinition error

Consider this code:
template<typename T,typename K>
struct A{
friend std::ostream& operator<<(std::ostream& out, K x) {
// Do some output
return out;
}
};
int main(){
A<int,int> i;
A<double,int> j;
}
It does not compile, because the two instantiations of A instantiate the operator<< two times with the same signature, so I receive this error:
test.cpp:26:25: error: redefinition of ‘std::ostream& operator<<(std::ostream&, int)’
friend std::ostream& operator<<(std::ostream& out, K x) { return out; }
^
test.cpp:26:25: error: ‘std::ostream& operator<<(std::ostream&, int)’ previously defined here
How to fix this? How can I have a friend operator in a template, when that operator might have the same signature for two different instantiations? How can I solve this without triggering a redefinition error?
I don't really see any use in declaring a friend like this, nevertheless this is how you can do it:
template<typename T, typename K>
struct A{
template<typename L>
friend std::ostream& operator<<(std::ostream& out, L const &x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) {
// ...
return out;
}
LIVE DEMO
Edit:
Another option probably closer to what you want will be:
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x);
template<typename T, typename K>
struct A{
friend std::ostream& operator<<<K>(std::ostream& out, K const &x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, T const &x) {
// ...
return out;
}
LIVE DEMO
But really not sure why you want this. IMHO your design has serious flaws.
Your question is faulty in the following way.
Assuming it's a stub and your class has something private such that it needs to declare a friend, the purpose of doing so is that the friend is external to the class itself but has access to what is private within it.
In your case you are declaring streaming functions of a parameter as a friend. That is fine. It means if someone creates a class Bar and wants to define how a Bar is streamed their implementation may access anything in A<T,Bar> for any type T.
The clashing of your template with operator<<( ostream&, int) is not actually a problem as the compiler knows which one to pick. It will always pick the exact match non-templated over the templated one. Your problem is that you have 2 templated ones and the compiler cannot pick between them because they are both equally valid.
Maybe something like this is what you are really trying to achieve
template< typename X, typename Y >
struct A
{
friend void a_print( std::ostream& Y const & ); // foo external function with Y as parameter, can access this
};
std::ostream & operator<<( std::ostream & out, Bar const& bar )
{
a_print( out, bar );
return out;
}
void a_print( Bar const& bar, std::ostream & out )
{
// implement and call private members of A<Foo, Bar>
return out;
}
You could make the streaming template a friend and implement the one for Bar to stream using a specific implementation.
Factor the method out to a base class:
template <typename K>
struct ABase
{
friend std::ostream& operator<<(std::ostream& out, K x) {
// Do some output
return out;
}
};
template <typename T,typename K>
struct A : public ABase<K>
{};
If you want to stream an A object, the proper signature should have been
template<typename T,typename K>
struct A{
friend std::ostream& operator<<(std::ostream& out, const A& x) {
// Do some output
return out;
}
};
taking an A<T,K> for which you can access private members, not a K.
If there is no way to get an A from K (and cannot be if K is int), making <<(ostream&,K) a friend of A gives no benefits.

Using overloaded output operator for templated class: Undefined symbols for architecture x86_64 [duplicate]

I am trying to overload << operator and using friend function.
Below code chunk works just fine.
template <class T>
class Mystack{
friend std::ostream& operator<<(std::ostream& s, Mystack<T> const& d)
{
d.print(s);
return s;
}
};
Since it is friend function I would obviously want to define it outside the class without using scope resolution operator. But when I try that I get error.
template <class T>
class Mystack{
friend std::ostream& operator<<(std::ostream& s, Mystack<T> const& d);
};
template <class T>
std::ostream& operator<<(std::ostream& s, Mystack<T> const& d)
{
d.print(s);
return s;
}
Below is the code snippet for main
Mystack<int> intstack;
std::cout << intstack;
ERROR : Unresolved extrernal symbol.
P.S: Its not the complete running code. Just a sample. Kindly bear.
friend std::ostream& operator<<(std::ostream& s, Mystack<T> const& d);
declares and befriends a non-template operator<< function. So Mystack<int> would have as its friend a non-template function std::ostream& operator<<(std::ostream& s, Mystack<int> const& d);, etc.
template<class T>
std::ostream& operator<<(std::ostream& s, Mystack<T> const& d)
{
d.print(s);
return s;
}
defines an operator<< function template.
The two are not the same. When you write std::cout << intstack;, the overload resolution rules resolve it to the non-template operator<< function you declared, but it isn't defined, so you get a linker error.
There's no way to define a non-template function for every instantiation of a class template outside the class template. You can, however, befriend a specialization of your operator<< function template:
// forward declarations
template <class T>
class Mystack;
template <class T>
std::ostream& operator<<(std::ostream& s, Mystack<T> const& d);
template <class T>
class Mystack
{
friend std::ostream& operator<< <T>(std::ostream& s, Mystack<T> const& d);
// ^^^
};
or befriend every specialization of the function template, which is worse from an encapsulation point of view (since, e.g., operator<< <int> would be a friend of Mystack<float>):
template <class T>
class Mystack
{
public:
template <class U>
friend std::ostream& operator<<(std::ostream& s, Mystack<U> const& d);
};
or just define the friend function inside the class.