Правило, для какой функции перегрузка специализироваться - PullRequest
2 голосов
/ 28 февраля 2020

Рассмотрим код:

#include <iostream>

template <typename T>
void f(T)
{
    std::cout << "Version 1" << std::endl;
}

template <typename T>
void f(T *)
{
    std::cout << "Version 2" << std::endl;
}

template <>
void f<>(int *)
{
    std::cout << "Version 3" << std::endl;
}

int main()
{
    int *p = nullptr;
    f(p);
    return 0;
}

Этот код выведет Version 3. Происходит то, что правила перегрузки функций рассматривают первые две версии void f (третья версия является специализацией и не участвует в перегрузке) и решают, что вторая версия является лучшей версией. Как только это решение будет принято, мы увидим, существуют ли какие-либо специализации для второй версии. Существует, и мы используем его.

Тогда мой вопрос: как компилятор узнал, что моя явная специализация была специализацией второй перегрузки, а не первой? Я не предоставил ему параметр шаблона, чтобы он мог сделать этот выбор. Это просто тот случай, когда решение о том, какая функция должна специализироваться, следует тому же / тому же правилу, что и решение о том, какую перегрузку вызывать (если она вызывала функцию)? Это имело бы какой-то смысл ...

1 Ответ

2 голосов
/ 28 февраля 2020

Этот пример есть в template_argument_deduction # Explicit_instantiation

Вывод аргумента шаблона используется в явных экземплярах, явных специализациях и тех объявлениях друзей, в которых идентификатор объявления объявлен Для специализации шаблона функции (например, friend ostream& operator<< <> (...)), если не все аргументы шаблона явно заданы или по умолчанию, вычет аргумента шаблона используется для определения того, на какую специализацию шаблона ссылаются.

P - это тип шаблона функции, который рассматривается как потенциальное совпадение, а A - это тип функции из объявления. Если нет совпадений или более одного совпадения (после частичного упорядочения), объявление функции некорректно:

template<class X> void f(X a);  // 1st template f
template<class X> void f(X* a); // 2nd template f
template<> void f<>(int* a) { } // explicit specialization of f
// P1 = void(X), A1 = void(int*): deduced X = int*, f<int*>(int*)
// P2 = void(X*), A2 = void(int*): deduced X = int, f<int>(int*)
// f<int*>(int*) and f<int>(int*) are then submitted to partial ordering
// which selects f<int>(int*) as the more specialized template
...