【问题标题】:Function specialization in template class for float and double literals用于浮点和双精度字面量的模板类中的函数特化
【发布时间】:2025-12-20 20:50:12
【问题描述】:

我正在尝试找到在模板类方法中使用常量数字文字的解决方案。我正在制作一些与浮点或双精度类型一起使用的数学模板类。问题是文字因数据类型而异(例如,浮点数为“0.5f”,双精度数为“0.5”)。到目前为止,我提出了两个解决方案。第一个的一些假设代码:

template <typename T>
class SomeClass
{
    public:
        T doSomething(T x);
};

template <>
float SomeClass<float>::doSomething(float x)
{
    float y = 0.5f;
    /*
     * Do computations...
    */
    return x;
}

template <>
double SomeClass<double>::doSomething(double x)
{
    double y = 0.5;
    /*
     * Do computations...
    */
    return x;
}

上面的方法强制为每一种使用它的类型重写整个方法。

另一种方法:

template <typename T>
class SomeClass
{
    public:
        T doSomething(T x);

    private:
        T getValue();
};

template <typename T>
T SomeClass<T>::doSomething(T x)
{
    T y = getValue();
    /*
     * Do computations...
    */
    return x;
}

template <>
float SomeClass<float>::getValue()
{
    return 0.5f;
}

template <>
double SomeClass<double>::getValue()
{
    return 0.5;
}

这不需要为特定类型多次编写相同的方法,但需要为每个需要在方法内部使用的“幻数”有很多 getValue() 方法。

还有另一种“更优雅”的方法来解决这个问题吗?

【问题讨论】:

  • 如果它只是关于文字,我认为你可以使用强制转换 static_cast()
  • 我没有在我的问题中提到它,但我想避免任何转换,无论是显式的还是隐式的。

标签: c++ function templates literals specialization


【解决方案1】:

假设实际上有必要在两个特化中使用不同的值(例如,对于 0.5 和 0.5f 来说没有必要),那么打字就会少很多:

template <typename T>
class SomeClass
{
  public:
    T doSomething(T x);

  private:
    static const T magic_number_1;
};

template <typename T>
T SomeClass<T>::doSomething(T x)
{
  T y = magic_number_1;
  /* 
   * Do computations...
  */
  return x;
}

template <>
const float SomeClass<float>::magic_number_1 = 0.5f;

template <>
const double SomeClass<double>::magic_number_1 = 0.5;

【讨论】:

  • 对,这似乎比单独的 getValue() 方法更好。
【解决方案2】:

感谢大家的回答和cmets。我允许自己对到目前为止所说的内容进行总结并添加我的结论。

我将实现一些数学类模板,以便实例化以与浮点或双精度类型一起使用。需要在类内部使用一些数字文字。它们将是一些常用的数字文字和常量,例如 0.0、0.5、1.0、pi 等。我正在寻找一种解决方案,使类实例化可以根据其类型在不同的文字上工作。

是否使用 float 和 double 字面量?

关于是否费心为 float 和 double 使用单独的文字的话题稍作讨论。这可能是由我在问题中给出的一个不幸的例子引起的。在示例中,文字无论如何都会在编译时转换为正确的类型,因此不会造成任何伤害。但一般情况下会出现需要在表达式中使用字面量的情况,例如:

float foo(float x)
{
    return x * 3.14;
}

这将强制编译器将 x 转换为双精度,进行计算,然后将结果转换回浮点数。这种行为的利弊:

优点:

  • 精确增益,因为实际计算将以双倍完成 精度。

缺点:

  • 如果性能是一个问题,这可能会导致更快以及 执行速度较慢,具体取决于环境和平台。这 根据实现引入了一些性能变化,其中 就我而言,不好。
  • 引入了计算不一致,因为某些操作将 根据字面量的使用,在浮点数和一些双精度数上完成。这 也可能会暴露一些错误。
  • 首先打破了为浮点数专门化类的想法 因为无论如何,内部计算都会在双精度数上完成。

总之,目标是使类实例化在正确的类型上工作,而无需任何额外的转换。在任何地方都使用双精度字面量(例如 0.5)并保留对编译器的正确转换的想法不是一种选择。

关于这个主题的更多信息:Should we generally use float literals for floats instead of the simpler double literals?

可能的解决方案?

  • 为每个模板实例化类型专门化方法,其中 必须使用文字。这可能是最糟糕的解决方案,因为它 强制编写两次相同的代码,对 字面量。
  • 制作专门的getValue&lt;type&gt;() 方法,或作为Jonathan Wakely posted - 专门 成员。这可能会导致有一些愚蠢的命名成员或方法 在课堂上,例如getZeroPointFive&lt;float&gt;()
  • Mohammad 和 Tony Delroy 指出用 static_cast&lt;T&gt;() 会成功的。转换为正确的类型将 在编译时完成。

【讨论】:

  • 一个更好的解决方案已经出现......来自 Mohammad 的评论......在它们参与表达式之前强制转换值 ala static_cast(5.0)。我知道你不喜欢它,但它会是编译时间并且是用数字本地化的,而 getZeroPointFive 等则不是。
  • 感谢您指出这一点。我已将其添加到可能的解决方案中
【解决方案3】:

您不必担心这一点 - 使用 0.5,如果类型为浮点数,编译器仍会将其初始化为与您使用 0.5f 相同的值。

这有点啰嗦,但您可能想在这里通读我的回答中“支持多态性的其他机制”部分:Polymorphism in c++

对于整个函数中浮点常量的更一般用法 - 特别是在比较和表达式中 - 值得阅读下面提到的链接 bluemess....

【讨论】:

  • 假设我将使用“0.5”字面量。这不会导致隐式(运行时?)转换在某个时候浮动吗?在我给出的示例中,它可能并不重要,但总的来说我宁愿避免转换。
  • 这将是一个编译时转换。
  • 我发现在某些情况下使用“0.5”字面量表示浮点数会导致多次转换,此处解释:Should we generally use float literals for floats instead of the simpler double literals?
  • @bluemass:对于问题中所示的分配,您可以期望它在编译时完成......(当然,即使没有优化,GCC 4.5.3 也会这样做)。对于其他计算,它肯定会导致与 double 之间的转换,但通常没关系,因为它减少了舍入误差。它可能更快或更慢,具体取决于硬件。
最近更新 更多