Разрешение перегрузки шаблонов: что происходит при совпадении нескольких шаблонов? - PullRequest
7 голосов
/ 27 сентября 2019

Следующая программа печатает T,T.

#include <iostream>

template<typename T>
void f(T x, T y) {
  std::cout << "T,T\n";
}

template<typename T1, typename T2> 
void f(T1 x, T2 y) {
  std::cout << "T1,T2\n";
}

int main() {
  f(1, 1); 
  return 0;
}

Не имеет значения, какой шаблон стоит первым в коде.

Я бы ожидал, что разрешение перегрузки здесь будет неоднозначным.T, T1 и T2 должны быть выведены как int, что делает оба шаблона точно совпадающими с сайтом вызова.

Я не смог найти никаких правил разрешения (https://en.cppreference.com/w/cpp/language/overload_resolution), чтобы объяснить, почему он выбрал бы первый шаблон.

Я проверил с clang++ -std=c++17, на случай, если это имеет значение.

Ответы [ 2 ]

5 голосов
/ 27 сентября 2019

Частичное упорядочение перегруженных шаблонов функций выполняется, чтобы определить, какой из них следует выбрать.

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

В частности, частичное упорядочение происходит в следующих ситуациях:

1) разрешение перегрузки длявызов специализации шаблона функции

template<class X> void f(X a);
template<class X> void f(X* a);
int* p;
f(p);

2) ...

...

Неформально «А более специализирован, чем В» означает «А принимает меньше типовчем B ".

1-я перегрузка выбрана потому, что она принимает аргументы только одного типа, а 2-я может принимать аргументы с двумя независимыми типами.

0 голосов
/ 27 сентября 2019

Возможно, часть ответа здесьсоздается, неявная реализация.Список аргументов шаблона не должен предоставляться, если он может быть выведен из контекста

Компилятор связывает вызов f(1, 1) с созданием экземпляра f<int>.Когда в шаблоне удаляется первый шаблон (template<typename T> void f(T x, T y)), компилятор связывает вызов f(1, 1) с созданием f<int, int>.Вы можете вызывать каждый экземпляр, используя явное указание типов:

f(1, 1);
f<int>(1, 1);
f<int, int>(1, 1);

вывод:

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