采用此功能模板:
template <typename T>
T divby2(T a)
{
return .5 * a;
}
是否存在指定(.5
),double
常量的方法,以便在T
时不会在运行时将其转换为T != double
(比如,当T
是float
时)?
关于.5常数的替代规范的一些想法:
template <typename T>
T divby2(T a)
{
return T(.5) * a;
}
template <typename T>
T divby2(T a)
{
return (T(1) / T(2)) * a;
}
答案 0 :(得分:6)
在运行时没有关于转换的决定。是否将值转换为另一种类型的决定是在编译时进行的。
.5
将是双倍的。 a
将是您拥有的任何模板专精,即类型T
X
)将是operator*(double, T)
给出的任何值。所有内置数字的双倍,除了long double,它给出了一个很长的双倍T
,因此乘法返回的X
将转换为T
T(0.5)
将永远是T. 如果未定义任何转换或operator*
,则会出现编译时错误。类型与运行时无关(除非您有虚函数等)。
发表评论:T(.5)
是T类型的表达式。值的转换将概念在运行时进行。但是,允许编译器优化它,例如,如果T为int,编译器将使用T(.5)
实例化int(.5)
并立即将其优化为0
。
根据您的问题,我假设您可能不了解模板的性质。与 compiletime 中的模板进行评估和实例化,与其他语言中的泛型函数不同。模板实例化意味着编译器为您使用模板的每种类型生成独立函数。所以例如如果您在不同的地方使用T=double
,T=int
和T=long double
的该功能,就好像您已经编写了三个功能一样:
double divby2(double a)
{
return .5 * a;
}
int divby2(int a)
{
return .5 * a;
}
long double divby2(long double a)
{
return .5 * a;
}
在第一个函数中,根本不会发生任何转换,因为所有内容都是双倍的。在第二个函数中,编译器知道double乘以int得到一个double,但是double会被转换回int。您可能会收到有关此问题的警告。在第三个函数中,double和long double的乘法给出了long double。由于返回类型也是一个很长的双倍,一切都很好,你不会收到警告。