Search code examples
c++functiontemplatesfriend

How to define and use a friend function to a temlate class with the same template?


I have written the following code:

#include <iostream>
using namespace std;

template <class T>
class AA
{
  T a;

public:
AA()
{
 a = 7;
}

friend void print(const AA<T> & z);
};

template <class T>
void print(const AA<T> & z)
{
    cout<<"Print: "<<z.a<<endl;
}

void main()
{
AA<int> a;
print<int>(a);
}

And getting the following error:

error C2248: 'AA<T>::a' : cannot access private member declared in class 'AA<T>'
1>        with
1>        [
1>            T=int
1>        ]
1>        c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(7) : see declaration of 'AA<T>::a'
1>        with
1>        [
1>            T=int
1>        ]
1>        c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(30) : see reference to function template instantiation 'void print<int>(const AA<T> &)' being compiled
1>        with
1>        [
1>            T=int
1>        ]

What's wrong?

P.S. I am using Visual Studio 2008.


Solution

  • The problem is that when you do something like

    template<class T>
    class AA {friend void print(const AA<T>&);};
    

    and you instantiate AA with like this

    AA<int> a;
    

    the friend declaration will be instantiated like

    friend void print(const AA<int>&);
    

    which is a non-template function! This means the compiler will not match the friend declaration with your print function.

    The solution is basically to declare print before AA and explicitly tell the compiler that your friend declaration is talking about a template function. Like this:

    #include <iostream>
    using namespace std;
    
    //forward declare AA because print needs it
    template<class T>
    class AA;
    
    //declare print before AA to make the friend declaration
    //match with this function
    template<class T>
    void print(const AA<T> & z);
    
    template <class T>
    class AA
    {
            //the <> is needed to make sure the compiler knows we're
            //dealing with a template function here
            friend void print<>(const AA<T> & z);
    
        public:
            AA() {a = 7;}
    
        private:
            T a;
    };
    
    //implement print
    template<class T>
    void print(const AA<T> & z)
    {
        cout<<"Print: "<<z.a<<endl;
    }
    
    int main()
    {
        AA<int> a;
        print(a);
    }
    

    It is interesting to see what happens if you do not add the <> in the friend declaration. You will get a linker error. Why? Well, because the compiler cannot match the friend declaration with your template print function, it will implicitly assume a function with prototype

    void print(const AA<int>&);
    

    exists. Since I didn't explicitly provide a template parameter to the call to print (which isn't necessary because the compiler should be able to deduce this), the compiler will match this call with the function declared as friend. This function is nowhere implemented, hence the linker error.