Разность функциональных шаблонов

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

void foo(int)
{
    std::cout << "int";
}

void foo(char)
{
    std::cout << "char";
}

foo(42) int. Но для шаблона функции:

template <int T>
void bar()
{
    std::cout << "int T";
}

template <char T>
void bar()
{
    std::cout << "char T";
}

bar<42>() - неоднозначный вызов. Это происходит, даже если я использую char, например bar<'a'>(). Почему одно работает, а не другое?

Ответы

Ответ 1

Стандартная N4140 (кредит идет M.M) дает это объяснение и образец в 14.8.2 Вывод аргумента шаблона:

9 За исключением случаев, описанных выше, использование недопустимого значения не должно приводить к вычету типа. [Пример: В следующем примере 1000 преобразуется в signed char и приводит к определенному реализацией значению как указано в (4.7). Другими словами, оба шаблона считаются даже при 1000, когда они преобразуются в подписанный char, приводит к определенному реализацией значению.

template <int> int f(int);
template <signed char> int f(int);
int i1 = f<1>(0);    // ambiguous
int i2 = f<1000>(0); // ambiguous

- конец примера]

Однако обратите внимание, что в последующих черновиках правила изменяются потому что:

Это уже не корректно, даже игнорируя тот факт, что некоторые реализации могут представлять значение 1000 в качестве аргументов signed char: integer и перечисления, не являющихся типом шаблонов, теперь преобразуются в константные выражения (14.3.2 [temp. arg.nontype], пункт 1), а преобразованные константные выражения запрещают сужение конверсий (5.20 [expr.const], пункт 3).

Предлагаемый образец:

template <int> int f(int);
template <signed char> int f(int);

int i1 = f<1000>(0); // OK
int i2 = f<1>(0);    // ambiguous; not narrowing

Ответ 2

Существует разница между выборами перегрузки и специализаций. Разрешение перегрузки определяет неявные преобразования. Для преобразования 42 в int преобразования не требуется преобразование, поэтому это Exact Match, которое превосходит неявное преобразование, необходимое для 42 - char.

С другой стороны, специализация "перегрузка" в шаблоне функций использует правила частичного заказа, в которой используется вычитание аргумента шаблона, чтобы определить, что является более "специализированным" чем другой. Не вдаваясь в подробности, вычет не прерывается для int или char со значением 42, поэтому они оба одинаково специализированы. Если бы вы использовали значение вне диапазона подписанного char, i.e 128, вывод был бы неудачным, и была выбрана специализация int.

Ответ 3

В соответствии с этим веб-сайтом, который содержит очень хорошие примеры и объяснения, "специализация шаблонов функций не перегружает". Вот почему вы получаете call to 'bar' is ambiguous.