如何避免这个模板代码中的除零警告?

8

我有一个用于定点算术的类,下面是重要部分:

template <typename I, I S>
struct fixed
{
    I value;

    fixed(I i) : value(i * S) {}

    template <typename J, J T> fixed(const fixed<J, T> &fx)
    {
        if (S % T == 0)
            value = fx.value * (S / T);
        else if (T % S == 0)
            value = fx.value / (T / S);
        else
            value = S * fx.value / T;
    }

    static_assert(S >= 1, "Fixed-point scales must be at least 1.");
};

在GCC 4.4.5上,以下代码行:
fixed<int, 8> f = fixed<int, 2>(1);

生成错误:
fixed.hpp: In constructor ‘fixed<I, S>::fixed(const fixed<J, T>&) [with J = int, J T =     2, I = int, I S = 8]’:
fixed.hpp:81: error: division by zero

当代码中存在常量零除法时——T/S或S/T之一必须为零才能使规模不相等——如果S%T == 0(且S不为0),则S/T不为零。 GCC似乎只做了足够的优化,以确定我的分支中有一个保证会除以零,但没有足够的优化来确定保证不运行的分支。

我可以在文件中加入#pragma GCC diagnostic ignored "-Wdiv-by-zero",但这可能掩盖了真正的警告。

如何处理这种情况?(或者我的分析完全错误,我确实有一个真正的运行时除以零?)


如果 T % S == 0,那么 fx.value / (T / S); 不就等同于 S * fx.value / T 吗? - Jonas Bötel
1
有趣。我在 VC 上尝试了。const int b = 0; int a = 3/b; /错误/。const int b = 0; 如果 (b!=0) int a = 3/b; /仍然错误,有时这只是愚蠢编译器的问题../ - user534498
1
@LumpN:只有当您拥有无限位精度来存储中间结果时才可以这样做。 - user79758
@user534498:我也没试过VC,但这些是模板参数而不是变量。在变量情况下的警告让我觉得很合理,因为如果已知 b 总是零,那么整个分支就是不必要的。所以可能 VC 弹出了错误,但我认为仍然有必要对此发出警告/错误。 - user79758
2个回答

7

像这样的东西?

template<int,int>
struct helper {
    static int apply(...) { return S * fx.value / T; }
};

template<int n>
struct helper<0,n> { // need 0,0 as well to avoid ambiguity
    static int apply(...) { return fx.value * (S / T); }
};

template<int m>
struct helper<m,0> {
    static int apply(...) { return fx.value / (T / S); }
};

helper<(S % T == 0), (T % S == 0)>::apply(...);

或者使用 mpl::bool_,您可以通过参数“专门化”函数。


0
你可以使用一个支持模板来进行除法运算,并在除数为0时将其特殊化为硬编码的任意值(假设不会被使用)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接