Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ different template methods called on same variable

Could someone explain why once is used method c(T*) and next time d<>(int*) ? methods c and d seems identical to me and I cannot figure out why is not the same type of method called.

#include <iostream>
using namespace std;

template<typename T>
void c(T){ cout <<"(T)" << endl; }

template<>
void c<>(int*){ cout <<"(int*)" << endl; }

template<typename T>
void c(T*){ cout <<"(T*)" << endl; }

template<typename T>
void d(T){ cout <<"(T)" << endl; }

template<typename T>
void d(T*){ cout <<"(T*)" << endl; }

template<>
void d<>(int*){ cout <<"(int*)" << endl; }

int main(){
    int i;
    c(&i);
    d(&i);
    return 0;
}

Output:

(T*)
(int*)
like image 404
zlenyk Avatar asked Jun 16 '14 13:06

zlenyk


2 Answers

You just stumbled on an ugly part of C++.

The overload resolution pass, during compilation, is about finding the best overload for the current code. It is executed on a set of function and function templates that was selected by the look-up phase, and aims at identifying one (and only one) overload that is better than others.

For function templates, they are segregated in two groups:

  • "base" function templates
  • specialized function templates

and the overload resolution process has two steps:

  1. Pick the best match among the regular function and "base" function templates
  2. If a "base" function template is selected by step 1., pick the best specialization (if any matches, otherwise use the "base")

In both of your examples, the best "base" function is c(T*) and d(T*), so this is the second step that differ. Why ?

Because, to be a specialization of a function template, said function template has to be declared first.

Thus:

  • c<>(int*) is a specialization of c(T)
  • d<>(int*) is a specialization of d(T*)

and therefore, when c(T*) is picked in step 1., then there is no better specialization whilst when d(T*) is picked, d<>(int*) is a better specialization.

Because this is tricky, the recommendation by experts... is NOT to use function template specialization. It just mixes weirdly with function template overload.

like image 139
Matthieu M. Avatar answered Nov 10 '22 05:11

Matthieu M.


template <typename T>
void c(T);      // 1: function template

template <>
void c<>(int*); // 2: specialization of 1

template<typename T>
void c(T*);     // 3: overload of 1

template<typename T>
void d(T);      // 4: function template

template<typename T>
void d(T*);     // 5: overload of 4

template<>
void d<>(int*); // 6: specialization of 5

// ...

int i;

c(&i);          // 3 is more appropriate overload than 1

d(&i);          // 5 is more appropriate overload than 4
                // and it has the suitable specialization 6

Diagram:

                    c        d
                   / \      / \
overloads         1  (3)   4  (5)   |
                  |            |    |  priority
specializations   2           (6)   V
like image 31
Constructor Avatar answered Nov 10 '22 04:11

Constructor