Шаблон вычитания и перегрузки - PullRequest
1 голос
/ 20 марта 2019

Это упражнение для начинающих c ++ 5th:

template <typename T> void f(T);                   //1
template <typename T> void f(const T*);            //2
template <typename T> void g(T);                   //3
template <typename T> void g(T*);                  //4
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42); g(p); g(ci); g(p2);
f(42); f(p); f(ci); f(p2);

А вот и ответ:

g(42);  //type: int(rvalue) call template 3  T: int          instantiation: void g(int)
g(p);   //type: int *       call template 4  T: int          instantiation: void g(int *)
g(ci);  //type: const int   call template 3  T: const int    instantiation: void g(const int)
g(p2);  //type: const int * call template 4  T: const int    instantiation: void g(const int *)
f(42);  //type: int(rvalue) call template 1  T: int          instantiation: void f(int)
f(p);   //type: int *       call template 1  T: int *        instantiation: void f(int *)
f(ci);  //type: const int   call template 1  T: const int    instantiation: void f(const int)
f(p2);  //type: const int * call template 2  T:int          instantiation: void f(const int *)

Мой вопрос: почему f(p) предпочитает создание экземпляра f(T) вместо f(const T *)

Ответы [ 2 ]

1 голос
/ 20 марта 2019

Вкратце, правила для включения шаблонов функций в разрешение перегрузки:

  1. Поиск имени определяет набор видимых функций, объектов и шаблонов функций.

  2. Каждый шаблон функции в наборе определяет свои аргументы шаблона из любых явных аргументов, вычетов и / или аргументов шаблона по умолчанию, и они заменяются, чтобы получить одну конкретную сигнатуру конкретной функции, если это возможно.(Если это невозможно, шаблон функции просто выбрасывается из набора. Это может произойти, если не удается вывести аргументы шаблона и если не удается подставить аргументы в сигнатуру, то есть правило «SFINAE».)

  3. Функции сравниваются с использованием нормальных правил разрешения перегрузки, при этом сигнатуры, полученные из шаблонов, обрабатываются точно так же, как если бы они были обычными не шаблонными функциями.

  4. Только если на шаге 3рассмотрим две функции неоднозначно, применяются эти прерыватели:

    а.Если одна сигнатура функции пришла из шаблона, а другая - нет, то функция без шаблона считается лучшей.

    b.Если обе подписи функций взяты из шаблонов, и один шаблон «более специализирован», чем другой, то более специализированный шаблон считается лучшим.(Вкратце, «более специализированный» означает, по сути, что мы можем доказать, что любые действительные аргументы для более специализированного шаблона также являются действительными аргументами для менее специализированного шаблона, но не наоборот.)

В выражении f(p) этого примера на шаге 2 шаблон # 1 выводит T=int*, а шаблон # 2 выводит T=int, поэтому сигнатуры:

void f(int*);        // from 1
void f(const int*);  // from 2

На шаге 3 аргумент pимеет тип int*, поэтому void f(int*); из # 1 использует преобразование идентификаторов (точное совпадение), а void f(const int*); из # 2 использует преобразование указателей, поэтому void f(int*); из # 1 выигрывает, и специализация шаблона функциитот, который назван.

Это правда, что шаблон # 2 void f(const T*); более специализирован, чем шаблон # 1 void f(T);.Но поскольку шаг 3 определил ответ, мы никогда не перейдем к шагу 4, так что это не имеет значения(Шаг 4 подходит для другого выражения f(p2).)

0 голосов
/ 20 марта 2019

Это не ответ, но в основном:

f(T) с T=int* является точным соответствием для int*

f(T const*) с T=int не является точным совпадением для int*.

Победа в точных матчах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...