1
2
3
4
5
6
7
8
template<typename T>
void Swap(T &a ,T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

When using template functions, the compiler generates the appropriate function definition based on the actual type.

Overloading templates

Not all types use the same algorithm, and it is possible to overload template function definitions just like regular functions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template<typename T>
void Swap(T &a ,T &b); //#1

template<typename T>
void Swap(T *a ,T *b,int n);//#2 The last parameter is the specific type

int main()
{
    int i =10,j=20;
    Swap(i,j);//Use #1
    
    const int Lim = 8;
    int d1[Lim]={0,1,2,3,4,5,6,7};
    int d2[Lim]={7,6,5,4,3,2,1,0};
    Swap(d1,d2,Lim);//Use #2
}
template<typename T>
void Swap(T &a ,T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

template<typename T>
void Swap(T *a ,T *b,int n)
{
    T temp;
    for(int i=0;i<n;i++)
    {
        temp =a[i];
        a[i]=b[i];
        b[i]=temp;
    }
}

Template Limitations

In some cases, the corresponding operation of type T only applies to arrays, and the template function does not work if T is a structure.

Similarly, as in if(a>b) , if T is a structure, then > does not hold.

Solutions.

  1. Overload operator symbols.
  2. Provide a concrete template definition for a specific type.

Show Concretization

When the compiler finds a concretization definition that matches a function call, it will use that definition and no longer look for a template.

  • For a given function name, there can be non-template functions, template functions, and display concretized template functions and overloaded versions of each.
  • Display-concretized prototypes and definitions start with template<> and indicate the type by name.
  • The calling order is: non-template functions > materialized template functions > template functions.
1
2
3
4
5
6
7
8
void Swap(job& ,job&);

template <typename T>
void Swap(T&,T&);

template<> void Swap<job>(job& ,job&);//Display Concretization
//The <job> in Swap<job> is optional because the argument type of the function indicates that it is a materialization of the job, so it can also be written as follows
template<> void Swap(job& ,job&);

Instantiation and Concretization

Note: A function template does not generate a function definition, he just generates a scheme for generating function definitions. When the compiler uses a template to generate a function definition for a specific type, it gets a template instance.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
template<typename T>
void Swap(T &a ,T &b);

int a =10,b=20;
Swap(a,b);//Because the parameters of type int are provided, a template instance of type int is automatically generated. This is == implicitly instantiated ==
//It is also possible to directly command the compiler to create a specific instance
//Show instantiation
template void Swap<int>(int &,int &);//Generate function definitions for int types using the Swap() template

//Display Concretization
template<> void Swap<int>(int& ,int&);
template<> void Swap(int& ,int&);
// The difference is that concretization is not using the Swap() template function to generate a function definition, but using a function definition specifically for the int type display definition
//Simply understood, concretization is the declaration of a function, while instantiation is the use of a template function
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
template<typename T>
T Add(T a,T b)
{
    return a+b;
}

int m=6;
double x=10.5;
Add<double>(x,m); //doesn't match Add(x,m) because one is an int and one is a double
    //Instantiate with Add<double> to force m to double

//But the same does not work for Swap, because Swap uses reference types
Swap<double>(m,x);//double& cannot point to int
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//Use Cases
template <typename T>
void Swap(T &,T &);

template<> void Swap<job>(job&,job&);//Concretization
int mian()
{
    template void Swap<char>(char& ,char&);
    
    short a,b;
    Swap(a,b);//Implicit instantiation
    
    job n,m;
    Swap(n,m);//Display Concretization
    
    char g,h;
    Swap(g,h);//Show instantiation
}

Determination of template function type

1
2
3
4
5
template<class T1,class T2>
void fun(T1 x,T2 y)
{
    ?type? s=x+y; //Because it is a template function, at this point the ?type? type is not determined
}

C++11 adds decltype keyword.

1
2
3
4
5
template<class T1,class T2>
void fun(T1 x,T2 y)
{
    decltype(x+y) s=x+y; //The type of s is the same as the type of x+y
}

Steps to use decltype(expression) var.

  1. If expression is not enclosed in parentheses, var is the same type as expression, including qualifiers such as const.

    1
    2
    3
    4
    5
    6
    
    double x =5.5;
    double& z =x;
    const double* pd;
    decltype(x) w; //w is of type double
    decltype(z) u; //u is double& type
    decltype(pd) v; //v is of type const double*
    
  2. If expression is a function call, var is of the same type as the return value. The compiler determines the return value type by looking at the prototype instead of actually calling the function.

  3. if expression is a left value, var is a reference to its type. Common cases are as follows.

    1
    2
    3
    4
    5
    6
    
    double x = 4.5;
    decltype((x)) r = x;//r is of type double&
    decltype(x) r = x;//r is of type double
    
    //brackets do not change the value and left-valuedness of expression
    //It can be understood that adding parentheses is just one way of decltype declaring references
    
  4. If the first 3 items are not satisfied, then var is the same type as expression

    1
    2
    3
    4
    5
    6
    
    int j=3;
    int &k=j;
    int &n=j;
    
    decltype(j+6) x; //x is int
    decltype(k+n) y;//y is int , although k and n are references, but k + n is not a reference is the sum of 2 int
    

If declared multiple times, you can combine typedef and decltype

1
2
3
typedef decltype(x+y) xytype;
xytype z = x+y;
xytype arr[10];

However, certain function templates that require the definition of return value types can still not be resolved, e.g.

1
2
3
4
5
template<class T1,class T2>
?type? fun(T1 x,T2 y) //The type cannot be determined at this point
{
    return x+y;
}

C++ new syntax auto h(int x,float y) -> double , this is called the posterior return type and auto is a placeholder.

1
2
3
4
5
template<class T1,class T2>
auto fun(T1 x,T2 y)->decltype(x+y) //Post type using decltype
{
    return x+y;
}