0

拿这个函数模板:

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

是否存在一种方法来指定 ( .5),一个double常量,以便它不会在运行时转换为Twhen T != double(例如,when Tis 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;
}
4

1 回答 1

6

在运行时没有关于转换的决定。是否将值转换为另一种类型的决定是在编译时做出的。

  • .5无论如何,将是双重的。
  • a将是您拥有的任何模板专业化,即类型T
  • 乘法的结果类型(我们称之为X)将是任何operator*(double, T)给出的。所有内置数字的双精度数,除了长双精度数,它给出长双精度数
  • 由于您要返回 a TX因此乘法返回的值将转换为 aT
  • 并且T(0.5)永远是T。

如果这些转换中的任何一个或operator*未定义,则会出现编译时错误。类型与运行时无关(除非您有虚函数等)。

对您的评论:T(.5)是 T 类型的表达式。值的转换在概念上将在运行时进行。但是,允许编译器对其进行优化,例如,如果 T 是 int,编译器将实例化T(.5)withint(.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 乘以 int 得到一个 double,但该 double 被转换回 int。您可能会收到关于此的警告。在第三个函数中,一个 double 和一个 long double 相乘得到一个 long double。由于返回类型也是 long double,所以一切都很好,您不会收到警告。

于 2013-05-16T10:20:28.077 回答