Templates and friends - c++

While reading from Thinking in C++ Volume 2, from the Templates in Depth chapter, I see that if you have a friendly function in a template class, you need to forward declaration that function. I made this example to test this, overlaoding the output operator:
#include <iostream>
using namespace std;
/*
template<class T>
class X;
template<class T>
ostream& operator << (ostream& os, const X<T>& x);
*/
template<class T>
class X {
T t;
public:
X(T i): t(i) {}
friend ostream& operator << (ostream& os, const X<T>& x)
{
return os << x.t;
}
};
int main()
{
X<int> a(1);
cout << a;
return 0;
}
But it works without the forward declaration, but then I test it with the definition of << outside of the class:
friend ostream& operator << <>(ostream& os, const X<T>& x); (inside of the class)
template<class T>
ostream& operator << (ostream& os, const X<T>& x)
{
return os << x.t;
}
I am not sure why with the definition inside of the class it doesnt apply, is it because you have to explicit say that the ostream operator function is a template ? (using <> ) ??
Sorry for the confusion.

Since it seems that my comment was satisfactory, here it is in form of an answer.
The C++FAQ Lite has a chapter on this, which, for the sake of completeness, boils down to two possible ways to convince the compiler while it is examining the body of the class X that the friend function operator<< is actually a function template.
One approach is, as you did, declare the function template operator<< before the class definition and use the <> in the friend line inside the class body, giving the remarkable syntax of operator << <>(.
The other approach is to define the entire body of the friend template function inside the body of class X, which makes the forward declaration unnecessary.

Related

How to define a friend function declared in a non template class internal to a template class outside of both classes?

I found "how to define a friend template function of a template class outside of its declaration" (SO/cppreference), but how to do that if we add another internal non template class in the mix?
I.e. how to (externally) define operator<< declared in class Internal from the following example:
#include <iostream>
template <typename T>
class External {
public:
explicit External(T initial) : value{initial} {}
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
friend std::ostream& operator<<(std::ostream& os, const Internal& i);
// ^^^ this one
/* body
{
return os << i.internal_value;
}
*/
T internal_value;
};
friend std::ostream& operator<<(std::ostream& os, const External& e)
{
return os << Internal{e};
}
private:
T value;
};
int main()
{
std::cout << External<int>{5};
}
Here's the issue. Despite the fact that External is a template and Internal is a dependent type. The friend function is not templated itself. Odd as it may seem, it doesn't depend on the template parameter.
When you define it inline, then each specialization of the template creates the associated friend function as well. But when it's not inline you need to provide the definition of the operator for each specialization explicitly. And you can't do that with a template, since the function is not a template.
So if you add this after the template declaration:
std::ostream& operator<<(std::ostream& os, External<int>::Internal const& i)
{
return os << i.internal_value;
}
It will build. And as you can see, only concrete types are being used in the function.
Obviously that isn't much of a solution. Any sensible person would want specializations of External to generate the friend definition as well. The way to accomplish that in a maintainable fashion is to keep the operator definition inline, but instead of doing the work there, delegate to a member function (which is dependent on the template parameter):
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
std::ostream& print(std::ostream&) const;
friend std::ostream& operator<<(std::ostream& os, Internal const& i)
{
return i.print(os); // Short and sweet on account of being inline
}
T internal_value;
};
//....
template<typename T>
std::ostream& External<T>::Internal::print(std::ostream& os) const {
// Provided outside of the class definition, can be as verbose as you like
return os << internal_value;
}

Template parameter shadows with friend?

In the following example which overloads << operator:
#include <iostream>
template <typename T>
class MyClass {
public:
MyClass(T X, T Y):x(X), y(Y) {}
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
private:
T x;
T y;
};
template <typename T>
std::ostream& operator <<(std::ostream &os, const MyClass<T> &cl)
{
os << cl.x << " " << cl.y;
return os;
}
int main()
{
MyClass<int> cl(1, 2);
std::cout << cl << std::endl;
}
I have searched other questions but I couldn't find why exactly do I need:
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
the U instead of T in the typename? Because in the end U and T are both ints.
You can't use template <typename T> again because, on the rest of the line, it wouldn't know which of the two Ts you mean. It's kind of like this, which is also an error:
void foo(int x) {
int x = 4;
cout << x; // which x?
}
The compiler is not smart enough to figure out that in this case you will always want the two Ts to be the same, much like the error in the foo function above would not go away if you only ever called foo(4) in your program.
But what you've realized here is that you don't actually need the template arguments for operator<< at all here! That's because in this context you know exactly what type you want to use, whch is MyClass<T>. Normally, you can get rid of template parameters when you know the exact types you want. This is called an explicit specialization, and would normally look something like this:
template <>
friend std::ostream& operator<< <T>(std::ostream& os, const MyClass<T> &cl);
Note the empty template argument list template <>, which says "I don't need template arguments" and then the <T> after the function name, which says, "because I want the template argument type to be exactly T", where T is already known within a particular instantiation of the MyClass template. However this does not work here, because there is simply a rule in the C++ language specification that explicit specializations aren't allowed in friend declarations. (I am not exactly sure what the rationale is behind this rule, but it's a rule.)
So since you can't re-use the identifier T, and you can't explicitly specialize, the only option remaining is to use some other identifier, like U, for the template parameter.

"X is not a member of Y" even though X is a friend of Y?

I am trying to write a binary tree. Why does the following code report error C2039, "'<<' : is not a member of 'btree<T>'" even though the << operator has been declared as a friend function in the btree class?
#include<iostream>
using namespace std;
template<class T>
class btree
{
public:
friend ostream& operator<<(ostream &,T);
};
template<class T>
ostream& btree<T>::operator<<(ostream &o,T s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
In
template <typename T>
class BTree
{
// ...
friend std::ostream& operator<<( std::ostream&, T );
// ...
};
you're telling the compiler that there is a non template free function
std::ostream& operator<<( std::ostream&, Type )
for whatever type you happen to instantiate BTree over. But you never
provide such a function. The definition you provide is for a member,
but as a member function, your operator<< takes too many parameters.
Given that BTree is a generic type, it shouldn't provide the means of
displaying its contained elements; that's up to the contained element
type. What would make sense is something like:
template <typename T>
class BTree
{
struct Node
{
// ...
void display( std::ostream& dest, int indent ) const;
};
// ...
void display( std::ostream& dest ) const;
friend std::ostream& operator<<( std::ostream& dest, BTree const& tree )
{
tree.display( dest );
return dest;
}
};
template <typename T>
void BTree::display( std::ostream& dest ) const
{
if ( myRoot == NULL ) {
dest << "empty";
} else {
myRoot->display( dest, 0 );
}
}
template <typename T>
void BTree::Node::display( std::ostream& dest, int indent ) const
{
dest << std::string( indent, ' ' ) << data;
if ( myLeft != NULL ) {
myLeft->display( dest, indent + 2 );
}
if ( myRight != NULL ) {
myRight->display( dest, indent + 2 );
}
}
By declaring the operator friend, you tell the compiler to look for a function
ostream& operator<<(ostream &,T);
where T is the exact same type the btree class template is instantiated with. (e.g. for btree<Node>, the actual signature would be ostream& operator<<(ostream &, Node); -- assuming you hace members i and n of type Node)
This function will have access to private and protected members (variables and functions) of the class btree<T> for all instances of T, but it is not actually a member of the class (as it would be without the friend keyword).
The operator definition you provide is for an operator that is a member of the template class btree, as if you have declared
template<class T>
class btree
{
public:
ostream& operator<<(ostream &,T);
};
This is due to the btree<T>:: prefix you included (that specifies which class the function/operator belongs to).
Since there is no corresponding operator declaration in the class (see the above description of the friend declaration), the compiler complains.
To fix it, you either
keep the friend declaration, remove the btree<T>:: prefix and template<class T> from the operator defintion and change the second parameter type to btree<Type>&, where Type is one of the types you expect the btree template to be instantiated with (e.g. Node) -- then supply similar defintions for other such types as well.
or remove the friend keyword from the declaration in the class and remove the T parameter from both the declaration and the definition as now the operator is supposed to work on the whole btree (which is implicitly supplied via *this).
Alternatively, you can experiment with declaring the friend operator as a template, but that requires some more modifications: (read more about forward declaration)
template<class T> btree; // forward declaration of class btree
// forward declare operator (or move definition here)
template<class T>
ostream& operator<<(ostream &o, btree<T>& s);
// declare operator as template friend
template<class T>
class btree
{
public:
friend ostream& operator<< <> (ostream &, bree<T>&);
// note <> after operator name to denote template with no new template parameters
};
Note that above I assumed that you want to output the whole tree (that is invoke the operator<< on a btree object). It is not clear from the code you have whether this is your intention (class btree does not have members i and n). If not, and the type you want to invoke the << operator on is the actual template parameter of btree, then you don't need to change the second parameter of the templated operator from T, but there is also no need to declare it as friend of class btree as the operator is independent of btree. You do need to declare it as friend of the class whose members i and n you are accessing in the definiton of the operator (e.g Node above), if i and/or n is private in that class. The notion about losing btree<T>:: (or Node::) still applies as the operator does not belong to any class.
Couple more things, assuming you go with the friend declaration:
The type of the second parameter to the operator should be btree<T>& (emphasis on &) as it is more efficient to pass a reference to the btree object than to copy the entire btree (or a shallow copy if you use pointers and go with the default copy-contructor)
the second parameter should also be marked const, as (presumably) you do not want to change the btree object during output. Be aware that in this case you will need to mark certain non-changing methods in btree<T> as const as well to allow it to compile. (See the FAQ on const correctness)
EDIT'd a few times to make it clear and ensure correctness
A friend function is granted the same access to members of a class that members get, but it is not a member.
That's the whole point of the friend keyword, to give this access to non-members.
Since your operator<< doesn't use btree<T>, there's no reason to make it a friend of btree<T>.
So I think you meant
friend ostream& operator<<(ostream &, const mydata&);
inside class mydata.
Replace:
template<class T>
ostream& btree<T>::operator<<(ostream &o,T s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
with:
ostream& operator<<(ostream &o, const mydata &s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
As Ben Voight mentions, the error is telling you that this function is not a member of btree. Also, you seem to be defining that function for mydata exclusively, since it's expecting s and i members.
EDIT
Because it's a friend function, C++ is a bit weird. See, friend functions aren't actually defined in the class, they're defined in a different namespace. You have to provide an output function used by operator<< inside the class definition if you want it to use a templated member function.
The reason I suggest the following method (stream_out) is to demonstrate an easy way to do it in a way that makes it a member and doesn't mislead readers of your code, because it isn't a clever hack.
94% of the time you can use a clever hack such as has been suggested in the comments, but it does not answer the fundamental question: your 'friend' function is not a member of your class unless its body is given in the declaration, period, nothing else to say on the matter.
(What is the other 6% of the time, you ask, that this is not OK? copy constructor nonsense, CLI, and other unspeakable bumps in the night.)
If you absolutely must include it outside, as a member function, you would do something like...
template<class T>
class btree
{
private:
int i;
int n;
void stream_out(std::ostream& o);
public:
friend std::ostream& operator<<(std::ostream& o, btree<T> & me) {
me.stream_out(o);
return o;
}
};
template <class T>
void btree<T>::stream_out(std::ostream& o)
{
o << i << '\t' << n;
}
EDITED to clear up the summary a bit.

How do you declare the friend of a generic class outside of the class decleration?

The following code works, but i would like to move ostream& operator<< outside of the class declearation as i have with hash::operator[].
#include<iostream>
#include<map>
using namespace std;
template <class T>
class hash {
private:
map<string, T> _map;
public:
T& operator[] (string x);
friend ostream& operator<<(ostream& out, const hash<T> &rhs) { return out << "test"; }
};
template <class T>
T & hash<T>::operator[](string x) {
return _map[x];
}
int main () {
hash<int> myobject;
myobject["a"] = 1;
cout << myobject["a"] << endl;
cout << myobject << endl;
return 0;
}
I have tried:
template <class T>
ostream& operator<<(...) {
return out << "test";
}
and
ostream& operator<<(...) {
return out << "test";
}
as well as a few other combinations to no avail.
Since it does not seem that this question is getting closed as exact duplicate, I will explain what your program does.
template <typename T>
class test {
int private_field;
friend std::ostream& operator<<( std::ostream&, test<T> const & );
};
// ???
int main() {
std::cout << test<int>() << std::endl;
}
Templates are instantiated on demand (unless you explicitly instantiate them), that means that in this particular program test is instantiated only as test<int>. When the compiler instantiates the template (because it was requested in main) it will process the template definition. At this point the behavior is similar to rewriting the code with the substituted type at the point of definition (in this case right before main):
class test<int> {
friend std::ostream& operator<<( std::ostream&, test<int> const & );
};
Now, if you look at the instantiated template, you can note that the friend declaration is befriending a non templated function. So in this particular program you can fill in the ??? with that particular function:
std::ostream& operator<<( std::ostream& o, test<int> const & t ) {
return o << t.private_field;
}
The problem here is that this is not easily extensible. The code of that operator<< is the same for test<int> than it is for test<double>, so there should be no need to rewrite the same function for all instantiating types!
At this point there are two options, the first one is, as you have already identified, providing the definition of the function inside the class. The compiler will then process and define the function whenever the type is being instantiated. This solution creates non-templated functions on demand for each template instantiation (which is the option I would do, even with the quirks and strangeness of lookup here).
Now, if you really want to avoid providing the definition inside the templates class, and you still want to provide a single implementation, then you have to resort to providing a templates operator<<. At this point you have two different options, you can declare all instantiations of the template (which I don't quite like, as it opens to too many others), or you can befriend a single specialization of the template function (cleaner regarding access, more cumbersome to write).
The first case is:
template <typename T>
class test {
template <typename U>
friend std::ostream& operator<<( std::ostream&, test<U> const & );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
The second case requires a couple of forward declarations:
template <typename T> test;
template <typename T> std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test {
friend std::ostream& operator<< <T>( std::ostream&, const test<T>& );
};
template <typename T>
std::ostream& operator<<( std::ostream&, test<T> const & ) { ... }
There is of course another option: do not declare friends at all. Provide a print(std::ostream&) public function in your class that has the implementation, and provide a non-templated operator<< that just calls print on the second argument.
You have to be careful when you use friend and template
#include<iostream>
#include<map>
template <class T>
class MyHash{
public:
// ... use your T template here
template <class U>
friend ostream& operator<<(ostream& out, const MyHash<U> &rhs);
};
// ...
template <class U>
ostream& operator<<(ostream& out, const MyHash<U> &rhs){ return out << "test"; }
you need to use a different template U because operator<< is a friend method (external), if we use T instead of U, we will have : ambiguous definition in template .
Change hash by MyHash to avoid ambiguities.
Edit :
The error that you get here is :
error C2676: '<' binaire : 'std::string' ne définit pas cet opérateur
ou une conversion vers un type acceptable pour l'opérateur prédéfini
because you forgot to include <string> in "hash.h". That header defines the < operator.
And also try moving the definition of operator[] and operator<< directly into "hash.h"
Both the declaration and definition of templates must be included. This is because in some compilers template functions cannot be compiled and linked independently, since they are generated on request for the specific types they are instantiated with.
Change the #include "hash.cpp" to #include "hash.h"

template class and insertion extraction overloaded

How can I make the insertion (<<) and/or extraction (>>) operator overloaded in a template class WITHOUT making it inline. I would like to have the << or >> operator as a friend class.
I know how to make it inline
example of inline in a matrix class
friend ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
...
// create the ostr
return ostr;
}
but I'd like to have the code outside of the templateclass definition.
g++ told me to add <> after the function name so I did but when I tried to instansiate a matrix of type SOMETYPE it gave me an error that it didn't know how to extract or insert for that type.
If you really want to define the operator externally and befriend only the operator instantiation that coincides in type with this template instantiation, the correct syntax is:
template <typename T> class test; // forward declare template class
template <typename T> // forward declare the templated operator
std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test { // define the template
friend std::ostream& operator<< <T>( std::ostream&, test<T> const & ); // befriend
};
template <typename T> // define the operator
std::ostream& operator<<( std::ostream& o, test<T> const & ) {
return o;
}
In most cases it is not worth the hassle to pull the definition out of the class, considering that you still need to provide it in a header and the extra work required.
Also note that there are slight differences for the compiler regarding lookup. In the case where the function is inlined inside the class definition, the compiler will not find that function unless one of the arguments is actually of the type of the template, so it effectively reduces the visibility and the amount of work that the compiler has to do (if the templated operator<< is defined outside of the class, the compiler will find it as a candidate for overload resolution in all places where it finds a << b, only to discard it in all cases where the second argument is not a test<T> (and it will show the templated operator as a candidate in all error messages where it cannot match operator<<, which is a long enough list already).
Try something like:
template <typename T> class Matrix;
template <typename T> std::ostream& operator<<(std::ostream& ostr, const Matrix<T>& m);
template <Typename T>
class Matrix
{
public:
friend ostream& operator<< <T> (ostream& ostr, const Matrix<K>& inputMatrix);
};
// This must be in the same translation unit as the class definition!
template<typename T>
ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
// ...
return ostr;
}
Translation unit reference
re-re-edited to addressed the comments made by aschepler and dribeas.
Place the code in the header, outside the class definition. Or, place it in a .tcc file and include it at the bottom of the header.