Reputation: 126223
I'm getting a spurious "warning: left shift count >= width of type" when compiling some template code with gcc:
template <int N> class bitval {
unsigned long val;
#pragma GCC diagnostic ignored "-Wall"
const bitval &check() {
if (N < sizeof(unsigned long) * CHAR_BIT && val >= (1UL << N)) {
std::clog << val << " out of range for " << N << " bits in " << std::endl;
val &= (1UL << N) - 1; }
return *this; }
#pragma GCC diagnostic pop
};
The problem being that when it is instantiated with N == 64, it gives the warning.
Now the warning is completely spurious, as the code checks for N being large enough that no check/mask is needed, so when N is 64, the shifts will never happen. But gcc warns anyways. So I'm trying to disable the warning, but I can't figure out the needed #pragma magic to shut it up...
Upvotes: 3
Views: 828
Reputation: 275405
Tag dispatching to the rescue:
const bitval& check() {
constexpr bool enough_bits = (N < sizeof(unsigned long) * CHAR_BIT);
using enough_bits_t = std::integral_constant<bool, enough_bits>;
return check( enough_bits_t{} );
}
const bitval& check(std::false_type /*enough bits*/) {
return *this;
}
const bitval& check(std::true_type /*enough bits*/) {
if (val >= (1UL << N)) {
std::clog << val << " out of range for " << N << " bits in \n";
val &= (1UL << N) - 1;
}
return *this;
}
The decision (are there enough bits) is a compile-time constant, so I calculate it as one.
I then build a type (std::true_type
or std::false_type
) based off that decision, and dispatch to one of two different overloads.
So the code where N
is too big to be shifted that far is never instantiated, and hence no warning. If there is a logic error in the decision, and the code is instantiated, I get a compiler warning instead of silence (had you managed to disable the warning, and you had a logic error, you'd get silent UB).
Upvotes: 3