如何消除模板代码中的“除以0”错误

时间:2014-11-14 04:57:34

标签: c++ templates visual-studio-2013 divide-by-zero

我正在使用一对整数模板参数来指定比率,因为我不能使用double作为模板参数。转换为双精度可以防止零三进制。这在早期版本的编译器中有效,但Visual Studio 2013出现错误:

error C2124: divide or mod by zero

以下是代码的简化版本:

template<int B1, int B2>
class MyClass
{
    const double B = (B2 == 0) ? 0.0 : (double) B1 / (double) B2;
    // ...
};

MyClass<0, 0> myobj;

我真的希望B从使用它的表达式中优化为零,所以我需要单行定义。我知道我可以使用模板参数<0, 1>来解决它,但我想知道是否有办法让编译器相信我的表达式是安全的?

3 个答案:

答案 0 :(得分:15)

我被告知的工作:

 const double B = (B2 == 0 ? 0.0 : (double) B1) /
                  (B2 == 0 ? 1.0 : (double) B2);

这避免了对短路评估的依赖,防止除以0;在分割之前进行条件选择。


最初的想法/也许是这样的......? (我认为B应为static constconstexpr,但我相信您可以对此进行排序......)

template<int B1, int B2>
struct MyClass
{
    const double B = (double) B1 / (double) B2;
};

template <int B1>
struct MyClass<B1, 0>
{
    const double B = 0.0;
};

如果MyClass中有许多其他内容,并且不想复制或放入基础等,您可以使用专业化方法将B计算移动到支持模板中上方。

答案 1 :(得分:2)

Visual Studio无法在编译时在三元操作中对B1,B2进行类型转换,但显式转换将起作用。

template<int B1, int B2>
class MyClass
{
    double d1 = (double)B1;
    double d2 = (double)B2;
    const double B = (B2 == 0) ? 0.0 : d1/d2;
    // ...
};

MyClass<0, 0> myobj;

答案 2 :(得分:2)

对于好奇 - 这是我最终得到的代码。它可能有助于在现实世界中看到它。

template<int B1, int B2, int C1, int C2>
class BicubicFilter
{
    // Based on the formula published by Don Mitchell and Arun Netravali at
    // http://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
public:
    BicubicFilter() : m_dMultiplier(1.0) {}
    double m_dMultiplier;
    double k(double x) const
    {
        const double B = (double) B1 / ((B2 == 0) ? 1.0 : (double) B2);
        const double C = (double) C1 / ((C2 == 0) ? 1.0 : (double) C2);
        x = fabs(x) * m_dMultiplier;
        if (x < 1.0)
            return ((2.0 - 1.5*B - C) * x*x*x) + ((-3.0 + 2.0*B + C) * x*x) + (1.0 - (2.0/6.0)*B);
        if (x < 2.0)
            return (((-1.0/6.0)*B - C) * x*x*x) + ((B + 5.0*C) * x*x) + ((-2.0*B - 8.0*C) * x) + ((8.0/6.0)*B + 4.0*C);
        return 0.0;
    }
};

对于图像大小调整操作,k函数每像素执行至少4次,因此效率至关重要。我想在编译时知道所有常量,因此编译器可以尽可能地简化表达式。

根据接受的答案,我原本希望创建一个Ratio模板类,只需将两个int s的比率设为constexpr double,并将其专门用于0, 0的参数{1}}。 Visual Studio 2013尚未实现constexpr,因此我不相信编译器会将其视为编译时常量。幸运的是,原始三元表达式的变化消除了错误。