Пользователь StoryTeller дал лучший прямой ответ из standard
. Я хотел бы подробнее остановиться на этом, приведя подробный пример того, как компиляторы относятся к этому:
Давайте посмотрим на ваш текущий код:
#include <iostream>
using namespace std;
template<typename T>
T add(double a, double b) {
return static_cast<T>(a + b);
}
int main() {
cout << add<int>(1.1, 1) << endl;
cout << add<double>(1.1, 1) << endl;
return 0;
}
Посмотрим, как с этим справится компилятор. Прежде чем мы это сделаем, запомните следующее: templates
необходимо знать во время компиляции и аналогично тому, как C ++ заменяет текст макросами и определяет, что он делает что-то подобное для templates
также, когда они становятся экземплярами.
Ваш шаблон функции имеет такую подпись: он будет генерировать функцию, которая ему когда-либо понадобится T
.
template<typename T>
T add(double a, double b) {
return static_cast<T>(a + b);
}
Однако в этом случае T
не является частью подписи. Подпись функции выглядит так:
::add<T>(double, double)
И так как templates
argument
относится к его типу return
, а не к одному из его parameters
, здесь он не действует.
Давайте посмотрим на это так, как если бы мы не использовали шаблоны. Только для демонстрационных целей: игнорируйте тот факт, что следующее создаст неоднозначные функции:
int add( double, double );
float add( double, double );
double add( double, double );
Теперь давайте применим вызовы функций в вашей основной сети без версии шаблона:
#include <iostream>
int main() {
std::cout << add( 1.1, 1 ) << '\n'; // <int> - reminder of original
std::cout << add( 1.1, 1 ) << '\n'; // <double> - ""
return 0;
}
Теперь, глядя на код выше, у вас точно такой же вызов функции. Итак, какую перегрузку вызывает add в этом случае? Это довольно просто; без использования template
и игнорирования ambiguity
, вышеуказанная функция вызовет double add( double, double )
.
Так как вышеприведенный вызовет ошибку компилятора из-за неоднозначности, давайте вернемся и применим template
, чтобы выяснить, почему эта двусмысленность не возникает с версией template
.
- Оригинальный код -
#include <iostream>
template<typename T>
T add( double a, double b ) {
return static_cast<T>( a + b );
}
int main() {
std::cout << add<int>(1.1, 1) << '\n';
std::cout << add<double>(1.1,1) << '\n';
return 0;
}
Давайте посмотрим, как компилятор обрабатывает это поэтапно:
-Шаг 1: - Разрешение имени, получение сигнатуры функции.
int main() {
std::cout << ::add<int>( 1.1, 1 ) << '\n';
std::cout << ::add<double>( 1.1, 1 ) << '\n';
return 0;
}
-Шаг 2: - Вызов функции и создание стека вызовов функции
int main() {
std::cout <<
::add<int>( 1.1, 1 ) {
return static_cast<int>( 1.1 + 1 );
}
<< '\n';
std::cout <<
::add<double>( 1.1, 1 ) {
return static_cast<double>( 1.1 + 1 );
}
<< '\n';
return 0;
}
-Шаг 3: - Выполнение всех инструкций в функции
int main() {
std::cout <<
/*::add<int>( 1.1, 1 ) {
return static_cast<int>( 1.1 + 1 );
}*/
return static_cast<int>( 2.1 );
<< '\n';
std::cout <<
/*::add<double>( 1.1, 1 ) {
return static_cast<double>( 1.1 + 1 );
}*/
return static_cast<double>( 2.1 );
<< '\n';
return 0;
}
-Шаг 4: - Возвращение результата обратно из функции и очистка стека вызовов функции
int main() {
std::cout <<
return 2;
<< '\n';
std::cout <<
return 2.1;
<< '\n';
return 0;
}
-Step 5: - Основная функция передает возвращаемые результаты в операторы потока на стандартный вывод на экран.
int main() {
std::cout << 2 << '\n';
std::cout << 2.1 << '\n';
return 0;
}
И это точно соответствует вашему выводу!
-Output-
2
2.1
Я надеюсь, что этот пробел поможет вам лучше понять templates
и понять, почему здесь нет двусмысленности, как если бы вы их не использовали. Суть в том, что здесь нет двусмысленности из-за того, что вы explicitly
создали экземпляры шаблонов функций.
Теперь попробуйте снова запустить вашу программу, но на этот раз не указывайте тип и позвольте компилятору implicitly
создать экземпляр шаблона функции. Я полагаю, вы получите ошибку компилятора!