Подтвердить что ты не робот

C++ различные методы шаблонов, вызываемые с одной переменной

Может кто-нибудь объяснить, почему однажды используется метод c(T*) и в следующий раз d<>(int*)? методы c и d кажутся мне идентичными, и я не могу понять, почему не называется тот же тип метода.

#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;
}

Вывод:

(T*)
(int*)
4b9b3361

Ответ 1

Вы просто наткнулись на уродливую часть С++.

Передача разрешения перегрузки во время компиляции - это поиск лучшей перегрузки для текущего кода. Он выполняется на наборе шаблонов функций и функций, который был выбран на этапе поиска и направлен на определение одной (и только одной) перегрузки, которая лучше других.

Для шаблонов функций они разделяются на две группы:

  • "базовые" шаблоны функций
  • специализированные шаблоны функций

и процесс разрешения перегрузки имеет два шага:

  • Выберите наилучшее соответствие между регулярными функциями и шаблонами функций "base"
  • Если на шаге 1 выбран шаблон "базовой" функции, выберите лучшую специализацию (если есть какие-либо совпадения, в противном случае используйте "base" )

В обоих примерах лучшая "базовая" функция - c(T*) и d(T*), поэтому это второй шаг, который отличается. Почему?

Поскольку, чтобы быть специализацией шаблона функции, этот шаблон функции должен быть объявлен первым.

Таким образом:

  • c<>(int*) является специализацией c(T)
  • d<>(int*) является специализацией d(T*)

и, следовательно, когда c(T*) выбирается на этапе 1., тогда нет лучшей специализации, а когда d(T*) выбрано, d<>(int*) - лучшая специализация.

Поскольку это сложно, рекомендация экспертов... НЕ использовать специализированную функцию. Он просто смешивается с перегрузкой шаблона функции.

Ответ 2

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

Диаграмма:

                    c        d
                   / \      / \
overloads         1  (3)   4  (5)   |
                  |            |    |  priority
specializations   2           (6)   V

Ответ 3

Разрешение перегрузки выбирает только базовый шаблон (или функцию без функции, если таковая имеется). Только после того, как будет решено, какой базовый шаблон будет выбран, и этот выбор заблокирован, будет ли компилятор оглядываться вокруг, чтобы увидеть, есть ли подходящая специализация этого шаблона, и если это поможет специализации.

Для функции c специализация void c<>(int*) предназначена для перегрузки void c(T), а для d специализация void d<>(int*) предназначена для перегрузки void d(T*).

Таким образом, в приведенном выше объяснении сначала void c(T) проверяется и игнорируется над лучшей перегрузкой void c(T*) (которая не имеет специализаций), которая печатается. Для d тоже перегрузка void d(T*) заблокирована, но затем отмечена специализация void d(int*) и затем выбирается.