Тип данных значения по умолчанию для аргумента функции шаблона отличается от экземпляра типа данных - PullRequest
0 голосов
/ 28 августа 2018
 #include <iostream>
 #include <string>

 template <typename T>
 void f(T x = std::string{""})
 {
   std::cout << '[' << x << ']' << std::endl;
 }

 int main()
 {
   f(23); // Case 1: Doesn't fail
   f<int>(); // Case 2: Compilation error
   f<int>(23); // Case 3: Doesn't fail
 }

Не должно случиться, что в случае 1 и 3 также произойдет сбой, поскольку шаблон функции создается int, а значение по умолчанию имеет тип std::string.

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

Должны ли Случаи 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);

Снова явно, и на этот раз вы предоставляете правильный тип аргумента на сайте вызова.

0 голосов
/ 28 августа 2018

Ответ, предоставленный @Abigail, объясняет, почему случаи 1 и 3 не терпят неудачу, позвольте мне дополнительно отметить, что шаблон функции не имеет такого большого смысла. Ожидается, что функция с одним параметром, имеющим значение по умолчанию, будет вызываться следующим образом:

void g(std::string = "") { /* ... */ }

g(); // Use default parameter
g("non-default");

Напротив, ваш шаблон функции может быть вызван с заданным параметром

f("non-default");

но не без параметров, потому что компилятор не выводит типы шаблонов из аргументов по умолчанию.

f(); // Doesn't compile

Я бы предложил изменить шаблон на

 template <typename T = std::string>
 void f(T x = T{})
 {
     // same as before
 }

, который исправляет экземпляр f().

0 голосов
/ 28 августа 2018

T x = std::string{""} выполняется только в том случае, если для x.

не указано аргумента
f(23)

неявное создание экземпляра f<int>. значение по умолчанию для x не используется, поскольку 23 предоставляется как литерал int.

f<int>()

сейчас T имеет тип int, но вы присваиваете x с std::string

f<int>(23)

T по-прежнему int, так же, как и в случае 1

...