4

这是我不理解的代码

#include<iostream>

using namespace std;

template <typename T> 
T calc(T, T) { cout << "template calc" << endl; }

double calc(double, double) { cout << "ordinary calc" << endl; }

template <> 
char calc<char>(char, char) { cout << "template specialisation calc" << endl; }

int main() {

   int ival;
   double dval;
   float fd;

   calc(0, ival); // calls the generic calc(T, T)

   // the following all call calc(double, double)
   calc(0.25, dval);
   calc(0, fd);
   calc(0, 'J');

   calc('I', 'J'); // calls calc(char, char)
}

calc 有 5 个函数调用,所以我将它们称为 1) - 5),具体取决于它们的位置。

1)有点道理。0 是整数,ival 是整数,调用 calc(T, T) 是有意义的。尽管如此,我觉得我对此的推理是错误的。毕竟,它们都是双精度数,所以如果调用 calc(double, double),那也是有意义的。所以在这里寻求澄清。

2) 没有戏剧,都是双打,调用 calc(double, double)。简单的。

3) fd 是一个浮点数。可以调用 calc(T, T) 或 calc(double, double)。因为 1) 导致了对 calc(T, T) 的调用,所以我假设这里也是如此,因为我们再次有一个参数为 0,但是,这调用了 calc(double, double)。所以这让我很困惑,特别是这和1)之间的区别

4) 我的第一个想法是 0 是一个有效字符,'J' 也是如此,所以它调用 calc(char, char)。它可能会使用常见的整数类型调用 calc(T, T)。但是不,两者都错了,它调用 calc(double, double)。我对这个很困惑。对我来说毫无意义。

5) 是有道理的,但前提是我应用与 4) 相同的逻辑,这在 4) 中是错误的,所以如果我要看到另一个使用模板的示例,我将不确定要应用什么逻辑。

所以寻找解释为什么这个程序做它做的事情。

谢谢。

4

2 回答 2

1

首先,当您在源代码中写入文字“0”时,它的类型为“int”。并且在寻找调用哪个函数时,编译器会选择最匹配的一个。如果不可用,编译器将进行一些隐式类型转换以使其工作。

1) 0 和 ival 都是 int

2)对于double和double,calc(double, double)完全匹配

3)对于int和float,没有找到匹配,所以都转换为double

4)对于int和char,同3)

5)对于char和char,calc(char, char)完全匹配

于 2012-11-03T08:32:39.803 回答
1

我建议您阅读重载解决方案

选择最合适的重载函数或运算符的过程称为重载决策。

假设 f 是一个重载的函数名。当您调用重载函数 f() 时,编译器会创建一组候选函数。这组函数包括所有名为 f 的函数,可以从调用 f() 的位置访问这些函数。编译器可以将名为 f 的那些可访问函数之一的替代表示作为候选函数包括在内,以促进重载解决。

在创建了一组候选函数之后,编译器创建了一组可行的函数。这组函数是候选函数的子集。每个可行函数的参数数量与您用来调用 f() 的参数数量一致。

编译器从一组可行函数中选择最佳可行函数,即当您调用 f() 时 C++ 运行时环境将使用的函数声明。编译器通过隐式转换序列来做到这一点。隐式转换序列是将函数调用中的参数转换为函数声明中相应参数的类型所需的转换序列。对隐式转换序列进行排序;一些隐式转换序列比其他的要好。最好的可行函数是其参数都具有比所有其他可行函数更好或排名相同的隐式转换序列的函数。编译器将不允许编译器能够找到多个最佳可行函数的程序。

1、2 和 5 都是完全匹配的,因此不需要转换。

为了解释 3 和 4,请注意,如果您删除该double, double函数,您的程序将无法编译。这是因为不能为 3 和 4 推导出模板参数(因为参数类型不匹配)。因此,只有该double, double函数被视为候选函数。

于 2012-11-03T08:37:52.557 回答