在模板中浮动转换

float conversions in templates

本文关键字:转换      更新时间:2023-10-16

取这个函数模板:

template <typename T>
T divby2(T a)
{
  return .5 * a;
}

是否存在一种方法来指定(.5),一个double常数,使它不会在运行时转换为T时,T != double(说,当Tfloat)?

关于。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;
}

在运行时不需要对转换做出决定。是否将值转换为另一种类型的决定是在编译时做出的。

  • .5将是double,无论如何。
  • a将是您拥有的任何模板专门化,即类型T
  • 乘法的结果类型(我们称之为X)将是operator*(double, T)给出的任何值。所有内置数字的双精度类型,除了长双精度类型,它给出长双精度
  • 由于您返回的是T,乘法返回的X将被转换为T
  • T(0.5)将始终是t

如果没有定义任何这些转换或operator*,则会得到编译时错误。类型与运行时无关(除非你有虚函数之类的)。

对您的评论:T(.5)是t类型的表达式。的转换将概念上在运行时进行。但是,编译器可以将其优化掉,例如,如果T是int,编译器将用int(.5)实例化T(.5),并可以立即将其优化为0

从你的问题来看,我认为你可能不知道模板的本质。与其他语言中的泛型函数不同,模板在编译时被求值和实例化。模板实例化意味着编译器为使用模板的每种类型生成独立的函数。例如,如果你在不同的地方使用T=double, T=intT=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类型。在第二个函数中,编译器知道double型与int型相乘得到double型,但该double型又被转换回int型。你可能会收到警告。在第三个函数中,双精度型和长双精度型的乘法得到长双精度型。因为返回类型也是一个长双精度类型,所以一切都很好,您不会得到警告。