mardi 31 août 2021

Class Templates and Friendship in C++

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 << .

Aucun commentaire:

Enregistrer un commentaire