问题
I have a class for fixed-point arithmetic, of which this is the salient portion:
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.");
};
On GCC 4.4.5, the following line of code:
fixed<int, 8> f = fixed<int, 2>(1);
Generates an error:
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
While there is a division by constant zero in the code - one of T/S or S/T must be zero for unequal scales - if S%T == 0 (and S is not 0), then S/T is not zero. GCC seems to be doing just enough optimization to figure out that one of my branches is guaranteed to divide by zero, but not enough optimization to figure out that branch guaranteed to not run.
I can throw #pragma GCC diagnostic ignored "-Wdiv-by-zero"
in the file, but that risks masking real warnings.
What's the appropriate way to handle this situation? (Or is my analysis totally wrong and I do have a real runtime division by zero?)
回答1:
something like?
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(...);
or using mpl::bool_
you could "specialize" functions through parameters.
回答2:
You could use a supporting template to do the division, and specialise it to hardcode an arbitrary value (given it won't be used) when the divisor is 0.
来源:https://stackoverflow.com/questions/5217811/how-can-i-avoid-a-warning-about-division-by-zero-in-this-template-code