用户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 );
现在让我们在没有模板版本的情况下应用 main 中的函数调用:
#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;
}
-第二步: - 调用函数,并创建函数的调用栈
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;
}
-第 5 步: - 主要功能是将返回的结果传递给流操作符到标准屏幕输出。
int main() {
std::cout << 2 << '\n';
std::cout << 2.1 << '\n';
return 0;
}
这与您的输出完全匹配!
-输出-
2
2.1
我希望这个分解可以帮助您更好地理解templates,并了解为什么这里没有歧义,就好像您没有使用它们一样。这里的底线是没有歧义,因为您explicitly 实例化了函数模板。
现在尝试再次运行您的程序,但这次不要指定类型,让编译器implicitly 实例化函数模板。我相信你会得到一个编译器错误!