Moule Lin
← All notes

Friends in Class Templates

Friend Template Functions in Class Templates

Three kinds of friend declarations can appear in a class template:
(1) A friend declaration of an ordinary non-template class or function, which grants friendship to that specific class or function.
(2) A friend declaration of a class template or function template, which grants access to all instances of the friend.
(3) A friend declaration that grants access only to a specific instance of a class template or function template.

(1) Ordinary friend:

template<class T>

class A{

   friend void fun();

//...

};
In this example, fun can access the private and protected members of any instance of A

(2) General template friendship

template<class type>

class A{

  template<classT>

   friend void fun(T u);

//...

};

Here the friend uses a template parameter different from the class’s; T can be any valid identifier. The friend function can access the data of any instance of A, whether A’s parameter is int, double or anything else.

(3) Specific template friendship

template <class T> void fun(T,u);//for a specific template friendship, this declaration is required

template<class T>

class A{

   friend voidfun<T>(T u);//this could also be friend void fun<char>(char u);

//...

};

Now fun can only access the data of a specific instance of the class. In other words, only a fun and an A with the same template argument are friends: if fun is called with template argument int, it only has access to A<int>. Of course, the T inside <> in friendvoid fun<T>(Tu); can be any type, such as int, double, etc.

 

 

 

Creating friend functions for a class is easy, but moving to templates tends to produce baffling linker errors.
I am not experienced enough to analyse this, so I will simply introduce two ways to define friend functions for class templates
  1 Closed form

template< typename T >
class MyClass
{
    friend void function( MyClass< T > &arg )
    {
        
     }
 };  Key point: the friend function is defined inside the template body.

       2 Open form
template< typename T >
class MyClass
{
    template< typename C >
    friend void function( MyClass< C > &arg );
 };

template< typename C >
void function( MyClass< C > &arg )
{
    
 }  Key point: a separate template is declared inside the template body. 
  
  3 Tell the compiler that the declared function is a template
#include <iostream>
using namespace std;

template < typename T >
class A
{
    friend ostream &operator<< < T >( ostream &, const A< T > & );
 };

template < typename T >
ostream &operator<< ( ostream &output, const A< T > &a )
{
    output << "overload succeeded" << endl;
    return output;
 }

int main()
{
    A< int > a;
    cout << a;
 }Key point: explicitly add the template declaration < T> after the overloaded operator or function name, telling the compiler that the friend function is a template with a matching type.

Recommendations:
If the function should correspond to the type the template is specialized with, use method 3 (explicit template declaration)
If the function should be independent of the template’s specialized type, use method 2 (nested template)
For short inline functions, use method 1