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.
Related
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';
}
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.
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.
This one compiles and works like it should (non-nested template):
#include <iostream>
template<typename T> class Z;
template <typename T>
std::ostream& operator<< (std::ostream& os, const Z<T>&) {
return (os << "Z");
}
template<typename T> class Z {
friend std::ostream& operator<< <> (std::ostream& os, const Z&);
};
int main () {
Z<int> z;
std::cout << z << std::endl;
}
This one doesn't compile (gcc 4.4 and gcc 4.6, in both 03 and 0x mode):
#include <iostream>
template<typename T> class Z;
template<typename T>
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
return (os << "ZZ!");
}
template <typename T> class Z {
public:
class ZZ {
friend std::ostream& operator<< <> (std::ostream& os, const ZZ&);
};
};
int main () {
Z<int>::ZZ zz;
std::cout << zz << std::endl;
}
The error message looks like this:
error: template-id ‘operator<< <>’ for ‘std::ostream& operator<<(std::ostream&,
const Z<int>::ZZ&)’ does not match any template declaration
error: no match for ‘operator<<’ in ‘std::cout << zz’
In the 0x mode the second error message is different, but the meaning is the same.
Is it possible to do what I want to do?
EDIT Apparently, there's an instance of non-deduced context here, which explains the error messages. The question, however, still stands: can I have a working operator<< for a class nested in a class template?
This is a general problem for functions:
template <typename C>
void func(typename C::iterator i);
Now, if I call func(int*), which value of C should I use ?
In general, you cannot work backward ! Many different C could have defined an internal type iterator that happens to be a int* for some set of parameters.
In your case, you are complicating the situation a bit:
template <typename T>
void func(typename Z<T>::ZZ const&);
But fundamentally this is the same issue, Z<T> is a template, not a full class, and you are asking to create a function for the inner type ZZ of this template.
Suppose I do:
template <typename T>
struct Z { typedef T ZZ; };
template <typename T>
struct Z<T const> { typedef T ZZ; };
Note: typical of iterators, the value_type is not const-qualified
Then, when invoking func(int), should I use Z<int> or Z<int const> ?
It is non-deducible.
And thus the whole thing is referred to as a non-deducible context, and the Standard forbids it because there is no sensible answer.
Rule of Thumb: be suspicious of typename in the parameters of a function.
Note: they are OK if another argument already pinned down the type, example typename C::iterator find(C&, typename C::const_reference); because once C is deduced, then C::const_reference may be used without trouble
Apart from the problem that the friend declaration doesn't match the operator template (perhaps fixable as)
class ZZ {
template<class U>
friend std::ostream& operator<<(std::ostream& os, const ZZ&);
};
you also have a problem with a "non-deduced context", which is what Matthieu links to.
In this template
template<typename T>
std::ostream& operator<< (std::ostream& os, const typename Z<T>::ZZ&) {
return (os << "ZZ!");
}
the compiler isn't able to figure out for what T's you parameter will match. There could be several matches, if you specialize for some types
template<>
class Z<long>
{
public:
typedef double ZZ;
};
template<>
class Z<bool>
{
public:
typedef double ZZ;
};
Now if I try to print a double, T could be either bool or long.
The compiler cannot know this for sure without checking for all possible T's, and it doesn't have to do that. It just skips your operator instead.
Matthieu explained the problem very well, but a simple work-around can be used in this case.
You can implement the friend function inside the class with the friend declaration:
#include <iostream>
template <typename T> class Z {
public:
class ZZ {
friend std::ostream& operator<< (std::ostream& os, const ZZ&) {
return os << "ZZ!";
}
};
};
int main () {
Z<int>::ZZ zz;
std::cout << zz << std::endl;
}
A different technique is to provide an out of line class template which works like a hook.
template <typename T> class ZZZ {
T &getDerived() { return static_cast<T&>(*this); }
T const &getDerived() const { return static_cast<T const&>(*this); }
protected:
~ZZZ() { }
};
template <typename T> class Z {
public:
class ZZ : public ZZZ<ZZ> {
};
};
template<typename ZZ>
std::ostream& operator<< (std::ostream& os, const ZZZ<ZZ> &zzz) {
ZZ const& zz = zzz.getDerived();
/* now you can use zz */
return (os << "ZZ!");
}
Using a friend function definition is preferable though. But it's good to know about alternatives.
My question ist related a bit to this one.
I want to overload the operator << for some class and I found two different notations that both work:
template <class T>
class A{
T t;
public:
A(T init) : t(init){}
friend ostream& operator<< <> (ostream &os, const A<T> &a); //need forward declaration
//template <class U> friend ostream& operator<< (ostream &os, const A<U> &a);
};
Do I define identical things with different notations? Or is the first version more restrictive in which instance (in this case only the instance with the same T as my class A) of << is friend of A?
The first version restricts the friendship to the operator<< for the specific type A<T> , while the second makes any operator<< that takes an A<SomeType> a friend.
So yes, the first one is more restrictive:
template<class T>
ostream& operator<< (ostream& os, const A<T>& a) {
A<double> b(0.0);
b.t; // compile error with version 1, fine with version 2
return os;
}
int main() {
A<int> a(0);
cout << a << endl;
}
It so happens that the definition of friend functions have an exception for templates. It allows you to write this:
template <class T>
class A{
T t;
public:
A(T init) : t(init){}
friend ostream& operator<<(ostream &os, const A &a)
{ // Implementation in the class
}
};
And it has the advantage of creating a normal function automatically created for each instance of A<T> you create.
For reference: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16