Должны ли Случаи 1 и 3 также потерпеть неудачу, потому что функция
шаблон создается с помощью int, а значение по умолчанию имеет тип
станд :: строка?
Нет, не должно. Смотрите ниже, почему. Если вы хотите, чтобы он потерпел неудачу, вы должны определить f()
как обычную функцию , получающую аргумент типа std::string
и , а не шаблон функции .
Имеется случай создания экземпляра аргумента по умолчанию , см. Здесь в [temp.inst] :
Если шаблон функции f
вызывается способом, который требует значения по умолчанию
используемый аргумент, поиск зависимых имен, семантика
ограничения проверяются, и создание экземпляра [...] выполняется так, как если бы аргумент по умолчанию был
инициализатор, используемый в специализации шаблона функции , [...] Этот анализ
вызывается экземпляр аргумента по умолчанию . экземпляр по умолчанию
Аргумент затем используется в качестве аргумента f
.
Когда вы пишете:
template <typename T>
void f(T x = std::string{""}){...}
это означает, что ""
является аргументом по умолчанию для x
только в случае, если вызов сделан без каких-либо аргументов . например, в вашем случае 2 .
Ваша шаблонная функция определенно отлично работает для int
или для других типов .
Например, здесь (Случай 1) :
f(23);
неявно установлен (по логическому выводу на основе типа аргумента) равным f<int>()
, так как 23
определяется в спецификации как int
литерал, Параметр x
типа int
получает значение не по умолчанию из 23
, которое вы указали на сайте вызова.
А здесь (Дело 2) :
f<int>();
- это именно то место, где вступает в действие стандартное предложение, приведенное выше: Вы успешно создаете экземпляр f()
, но для него не предоставляется никаких аргументов, следовательно, конкретизированный аргумент по умолчанию равен используется в качестве аргумента f
. Таким образом, компиляция завершается неудачно, так как это значение по умолчанию здесь для параметра x
определено равным std::string
, и преобразование из него в тип int
не применяется. Это фактически эквивалентно вызову f("")
для функции, объявленной void f(int x)
.
А вот (Дело 3) :
f<int>(23);
Снова явно, и на этот раз вы предоставляете правильный тип аргумента на сайте вызова.