给出教程中的以下函数模板。
template<class T>
double GetAverage(T tArray[], int nElements)
{
T tSum = T(); // tSum = 0
for (int nIndex = 0; nIndex < nElements; ++nIndex)
{
tSum += tArray[nIndex];
}
// Whatever type of T is, convert to double
return double(tSum) / nElements;
}
在第
行T tSum = T(); // tSum = 0
他们说它将调用特定类型的默认构造函数(基于我们称之为此函数的类型)。我怀疑这个调用是如何将值赋给tSum的,因为这会调用构造函数。但由于构造函数不返回任何内容如何将iSum初始化为0表示int或0.0表示为double。
答案 0 :(得分:6)
您正在阅读的教程会产生一些严重的术语扭曲/简化。声明说
T tSum = T();
调用“默认构造函数”不正确。从一般情况来看,很明显,类型T
很容易成为非类型。非类类型没有任何构造函数,但上面的初始化对它们也有效。
在这种情况下,正确的术语是值初始化。表达式T()
生成一个由 value-initialization 进程初始化的T
类型的临时对象。值初始化根据其自己的特定规则工作,并且它根本不涉及任何构造函数。对于非类类型以及某些类类的类型,它以完全无构造函数的方式进行。
例如,表达式int()
生成类型0
的值int
- 这就是类型初始化对类型int
(以及所有标量类型)的意义。当然,它不涉及任何“默认构造函数”,因为类型int
不可能有任何构造函数。
同样,表达式T()
不是构造函数调用,因为该教程似乎错误地说明了。表达式T()
实际上是一个没有操作数的函数式转换。如上所述,没有操作数的函数式转换产生了T
类型的值初始化临时对象。它不依赖于构造函数“返回”任何东西。
如果T()
表达式随后用作tSum
对象的初始化程序,则为临时值。此语法从tSum
调用T()
的复制初始化。
答案 1 :(得分:3)
声明
T tSum = T();
表示'使用默认构造函数构造T类型的临时,然后复制/移动构造tSum',参见C ++ n3376 ch8.5,p14 。允许编译器(并且可能会)将其优化为就地默认构造T tSum;
,参见C ++ n3376 ch12.8,p31,copy elision ,但复制/移动构造函数必须可用,请参阅C ++ n3376 ch12.8 p32 (考虑删除T的复制/移动构造函数,它将无法编译)。
答案 2 :(得分:1)
T()
实际上创建了一个T
类型的临时对象,调用默认构造函数来初始化它。然后你就拥有了临时对象。
所以
T tSum = T();
将使用tSum
的默认初始化临时实例初始化T
。
如果T
是带有构造函数的类,则所有这些似乎都是不必要的,但如果T
是基本类型(例如int
),则会将tSum
初始化为0
。因为当您编写模板时T
的性质未知,所以代码可以安全地使用它。