Рассмотрим следующий код:
#include <iostream>
#include <type_traits>
// Variadic version
template<class... Variadic>
void f(const Variadic&... variadic)
{
std::cout<<"variadic"<<std::endl;
}
// Single version
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type>
void f(const Single& single)
{
std::cout<<"single"<<std::endl;
}
// Main
int main()
{
f(); // variadic
f(42); // single : why?
f(std::string()); // variadic
f(42, 42); // variadic
return 0;
}
Я не понимаю, почему строка, помеченная как «одиночная», хорошо компилируется (в g ++ 4.6.3) и не создает проблемы с разрешением перегрузки. Говорит ли стандарт c ++ 11, что шаблонная функция с фиксированным числом параметров предпочтительнее, чем переменная функция, которая может иметь такую же сигнатуру?
Благодаря использованию второго параметра шаблона enable_if в «одиночной» версии компилятор считает эту версию более специализированным шаблоном для использования с типами, для которых он включен.
Он считается более специализированным, поскольку существуют типы, в которых шаблон экземпляра может быть создан, но «одиночный» не может.
Общее правило заключается в том, что более специализированный шаблон превосходит менее специализированный шаблон в разрешении перегрузки.
Это правда достаточно просто (два живых примера, gcc и clang)
template<class...T> void foo(T&&...) {std::cout << "...T\n";}
template<class T> void foo(T&&) {std::cout << "T\n";}
int main() {
foo(3);
}
Перегрузок не беру ...
кажется предпочтительным, когда выбор является явным параметром шаблона.
class=std::enable_if_t
не меняет это.
Так что обе ваши функции f
являются кандидатами, то компилятор предпочитает тот, у которого нет вариаций.
/ 8:
Если
A
был преобразован из пакета параметров функции иP
не является пакетом параметров, вывод типа завершается ошибкой. В противном случае, используя результирующие типыP
а такжеA
затем вычет производится, как описано в14.8.2.5
, ЕслиP
это пакет параметров функции, типA
каждого оставшегося типа параметра шаблона аргумента сравнивается с типом P идентификатора объявления
пакета параметров функции. Каждое сравнение выводит аргументы шаблона для последующих позиций в пакетах параметров шаблона, расширенных пакетом параметров функции. Если для данного типа вывод выполняется успешно, считается, что тип из шаблона аргумента является по меньшей мере таким же специализированным, как и тип из шаблона параметра. [
Пример:
template<class... Args> void f(Args... args); // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2> void f(T1 a1, T2 a2); // #3
f(); // calls #1
f(1, 2, 3); // calls #2
f(1, 2); // calls #3; non-variadic template #3 is more
// specialized than the variadic templates #1 and #
В частности, f(1,2)
пример.
Все enable_if_t
предложение делает это удалить версию с одним аргументом из рассмотрения, когда вы передаете std::string
как T
,