Explicit specialization of friend function for a class template - c++

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

Related

operator << overloading in a template function

I can't tell which part of this code is wrong. Error message is given below.
I want to overload the << operator so that I can write code like cout << tree. I looked up for information about templates, friend functions, operator overloading. But I still don't get why the error.
template <typename Value>
class Tree {
protected:
Node<Value>* root = NULL;
int size = 0;
std::ostream& _ostreamOperatorHelp(Node<Value>* node, int level,
std::ostream& os) {
...
}
public:
friend std::ostream& operator<< <Value>(std::ostream& os,
Tree<Value> const& tree);
};
template <typename Value>
std::ostream& operator<<(std::ostream& os, Tree<Value> const& tree) {
tree._ostreamOperatorHelp(tree.GetRoot(), 0, os);
return os;
}
Error message:
Tree.hpp:129:34: error: declaration of 'operator<<' as non-function
friend std::ostream& operator<< <Value>(std::ostream& ,
^~
Before you can befriend specific template specialization, you have to declare the general template function first like this:
template <typename Value>
class Tree;
template <typename Value>
std::ostream& operator<<(std::ostream& os, Tree<Value> const& tree);
template <typename Value>
class Tree {
protected:
Node<Value>* root = NULL;
int size = 0;
std::ostream& _ostreamOperatorHelp(Node<Value>* node, int level,
std::ostream& os) {
...
}
public:
friend std::ostream& operator<< <Value>(std::ostream& os,
Tree<Value> const& tree);
};
template <typename Value>
std::ostream& operator<<(std::ostream& os, Tree<Value> const& tree) {
tree._ostreamOperatorHelp(tree.GetRoot(), 0, os);
return os;
}

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

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 operator<< for a class with a collection of nested private classes?

I'd like to implement operator<< for my templated class so that it can print all the elements it contains to the given std::ostream&. The issue is that I can't seem to get it to recognize the function that I've defined.
The error I get is
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'Outer<int>::Inner')
os << inner << ", ";
~~~^~~~~~~~
Ideally I'd like not to have the function defined inline, but I can't even get it to work inline. In the code below you can see that I've commented out my attempt at defining it outside the class declaration. It produces the same error as above.
This question recommends making the operator a friend of the class. I've done that every way I can think of and it still doesn't work.
The code:
#include <iostream>
template<class T>
class Outer {
class Inner {
T item;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& inner) {
os << inner.item;
return os;
}
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
};
std::vector<Inner> inner_items;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& bar);
};
/*template<class T>
std::ostream& operator<<(std::ostream& os, const typename Outer<T>::Inner& bar) {
os << inner.item;
return os;
}*/
template<class T>
std::ostream& operator<<(std::ostream& os, const Outer<T> outer) {
for (typename Outer<T>::Inner inner : outer.inner_items) {
os << inner << ", ";
}
return os;
}
int main()
{
Outer<int> outer;
std::cout << outer;
}
Do not make the output operator for the nested types templates:
#include <iostream>
#include <vector>
template<class T>
class Outer {
class Inner {
T item;
friend std::ostream& operator<<(std::ostream& os, typename Outer<T>::Inner const& inner) {
os << inner.item;
return os;
}
friend std::ostream& operator<<(std::ostream& os, const Outer<T> outer);
};
template <typename T_>
friend std::ostream& operator<< (std::ostream&, Outer<T_> const&);
std::vector<Inner> inner_items;
};
template<class T>
std::ostream& operator<<(std::ostream& os, Outer<T> const& outer) {
for (typename Outer<T>::Inner const& inner : outer.inner_items) {
os << inner << ", ";
}
return os;
}
int main()
{
Outer<int> outer;
std::cout << outer;
}
There are a few const& sprinkled and a necessary friend declaration added, too.
You don't need (neither want) to templetize in Inner, just use the type:
class Outer {
class Inner {
T item;
friend std::ostream& operator<<(std::ostream& os, const Inner& inner) {
os << inner.item;
return os;
}
// ...
What you wrote above fails because you define a free function in Outer<T>::Inner which is operator<<(..). The second parameter is Outer<T_>::Inner and the compiler cannot go from Inner to the type in which it was defined.

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