Home > Net >  Class Templates and Friendship in C
Class Templates and Friendship in C

Time:09-17

I am trying to understand how templates and friendship works in C . So looking/trying out some examples by myself. One such example that i am unable to understand is given below:

VERSION 1

#include <iostream>

using namespace std;


//template<typename T> void func4();
//template<typename T> class NAME;
//   template<typename T> std::ostream& operator<< (std::ostream&, NAME<T> const&);
template<typename T>
class NAME {
   

    friend void func4<T>();
    friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
};
int main()
{
   cout << "Hello World" << endl; 
 
   return 0;
}

The above version 1 gives the following error:

prog.cc:13:17: error: variable or field 'func4' declared void
   13 |     friend void func4<T>();
      |                 ^~~~~
prog.cc:13:17: error: expected ';' at end of member declaration
   13 |     friend void func4<T>();
      |                 ^~~~~
      |                      ;
prog.cc:13:22: error: expected unqualified-id before '<' token
   13 |     friend void func4<T>();
      |                      ^

My first question is that even though i have commented the forward declarations for both func4 and operator<< template function, then how can i only get error only for func4? That is why is there no error for operator<<.

Note that i know we need forward declarations if we want to befriend a specific instantiation of a template. That is for

friend void func4<T>();

to work we need to comment out the statement

template<typename T> void func4();

and similarly for

friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);

to work we need to comment out corresponding forward declaration at the starting of the program. But when i comment out only template<typename T> void func4(); statement, the program works and and there is no error for operator<<. Again why aren't we getting the error for operator<< even though i have not comment out the corresponding forward declarations.

My second question is that is the statement

friend void func4<T>();

same as

friend void func4<>();

Similarly, is the statement

friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);

same as

friend std::ostream& operator<< <> (std::ostream&, NAME<T> const&);

My thinking is that the statement friend void func4<>(); is a specialization of the function template declared using the statement template <typename T> void func4();. Meanwhile when we write friend void func4<T>(); we are explicitly passing T so in this case when we write/call func4<int>(); the function template func4<int> will be intantiated and then occupy memory. On the other hand the specialised template function will already take up some memory since we have to provide its definition before we can call it. So can someone explain whether there is a difference when we use <T> and when we use <>. In summary, it seems to me that in case of <> a user supplied specialization will be used while in case of <T> a new intiantion will be created when we call func4(). So there is a difference because in case of <> we have to supply a definition which will already take some space(memory) while in the case of <T> func4 will only take space(memory) when we use/call it. Is this the correct conclusion?

My third question is that i have read that:

There is no way to explicitly specify template arguments to overloaded operators, conversion functions, and constructors, because they are called without the use of the function name.

According to the above quoted statement we cannot explicitly specify template arguments to overloaded operators, but then how can write friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&); as it overload operator << .

CodePudding user response:

Answer 1 There is no error for operator<< because you have used using namespace std; and in the std namespace there is already overloaded operator<<.

Answer 3 The quoted statement talks about calling(i.e., using) overloaded operators not defining/declaring them

Answer 2

VERSION 1

#include <iostream>

template<typename T> void func4();
template<typename T>
class NAME {
   

    //friend void func4<>();//this does not work because there is no way to deduce the template arguments
    friend void func4<T>();//this works because here we have explicitly passed T as the template argument

};
int main()
{
   std::cout << "Hello World" << std::endl; 
   NAME<int> n;
   return 0;
}

In version 1 we have a template function func4<>. Now when you write friend void func<T>(); and friend void func<>();, you are making the full specialization friend of the class template NAME<>. The reason friend void func<>(); does not work is that there is no way for template argument deduction to work in this case. While when you write friend void func<T>(); you have explicitly passed the template argument and so this works. This also means that both(friend void func<T> and friend void func<>();) are essentially the same specialization of the template function func<>. This will be more clear from my next example version 2.

VERSION 2

#include <iostream>

template<typename T> class NAME;
template<typename T> std::ostream& operator<<(std::ostream&, const NAME<T>& );
template<typename T>
class NAME {
   
    //both of the below friend declarations are equivalent
    friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&);//this works 
    friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&);//this works as well becasue of template argument deduction
    
};
int main()
{
   std::cout << "Hello World" << std::endl; 
   NAME<int> n;
   return 0;
}

In version 2 we have a overloaded operator template function. Both friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&); and friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&); are equivalent and are the same specialization of the overloaded template operator<< <T>. The only difference between them is that the second one uses template argument deduction. This is possible because unlike version 1, we have a function argument that depends on T this time so template argument deduction can work. This was not possible in case of function template func4<> because that function does not take any parameter that depends on the template parameter.

  • Related