如何替换双重类型的模板参数?

时间:2013-11-14 05:54:21

标签: c++ templates double

我有一个在Visual Studio 6中完美运行但在更现代版本中失败的模板类。

template<double B, double C>
class MyClass
{
    double k(double x) const
    {
        x = fabs(x);
        if (x < 1.0)
            return ((2.0 - 1.5*B - C) * x*x*x) + ((-3.0 + 2.0*B + C) * x*x) + (1.0 - 0.33333333*B);
        if (x < 2.0)
            return ((-0.16666667*B - C) * x*x*x) + ((B + 5.0*C) * x*x) + ((-2.0*B - 8.0*C) * x) + (1.3333333*B + 4.0*C);
        return 0.0;
    }
};

error C2993: 'double' : illegal type for non-type template parameter 'B'

我明白了,标准不允许使用double常量作为模板参数,VC ++最终符合要求。但是我应该用什么呢?表达式被重复计算并且是一个真正的瓶颈,我希望在编译时而不是运行时计算常量。

2 个答案:

答案 0 :(得分:1)

问题是将模板参数与程序范围的实例化集合进行匹配取决于完全相等,基于机器的浮点值的特定表示可能因平台而异。 (并且由于编译器不需要提供目标机器的编译时仿真,因此可能在编译时和运行时之间有所不同。)

解决方案是将double替换为其他一些明确的表示形式,例如比率,固定数量的分数(如百万),或者您自己的带有整数尾数和指数的浮点样式。

在C ++ 11中,您可以应用constexpr函数评估,在这种情况下会消除模板:

struct MyClass {
    constexpr MyClass( double b, double c )
        : b15( b * 1.5 ), b20( b * 2.0 ), b03( b * 0.33333333 ),
        /* etc */

    double b15, b20, b03, /* etc */

    double k( double x ) const {
        x = fabs(x);
        if (x < 1.0)
            return ((2.0 - b15 - C) * x*x*x) + ((-3.0 + b20 + C) * x*x) + (1.0 - b03);
        /* etc */
    }
};

这预先计算常量子表达式,并有效地将它们作为单个公共函数的运行时参数。但参数/成员对象访问可能会降低它的速度。

如果该函数始终可以内联,则该替代方案可能会以较少的工作量生成与原始模板类似的结果。

答案 1 :(得分:0)

如果你使用constexpr函数,它应该以最小的成本使用?:operator完成你想要的一切,因为你只能有一个return语句:

constexpr double k(double B, double C, double x) const
{
    x = fabs(x);
    return 
          (x < 1.0) ? 
               ((2.0 - 1.5*B - C) * x*x*x) + ((-3.0 + 2.0*B + C) * x*x) + (1.0 - 0.33333333*B)
        : (x < 2.0) ?
           ((-0.16666667*B - C) * x*x*x) + ((B + 5.0*C) * x*x) + ((-2.0*B - 8.0*C) * x)
           + 1.3333333*B + 4.0*C)
        : 0.0;
}

但是这要求x是文字(在编译时已知)

遗憾的是,您还不要按照

使用VS.

http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx

如果x是变量(在运行时更改)或使用VS:

只需删除上面的constexpr关键字即可。大多数优化很可能只是因为在编译时已知B和C这一事实 - 检查asm进行验证。 (升级不仅会增加严格性,还可能会改善优化)