在使用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
};
问题在于,当它以N == 64进行实例化时,会发出警告。
现在警告是完全虚假的,因为代码检查N足够大以至于不需要检查/掩码,因此当N为64时,移位将永远不会发生。但无论如何,gcc警告说。所以我试图禁用警告,但我无法找出所需的#pragma魔法来关闭它......
答案 0 :(得分:3)
标签调度救援:
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;
}
决定(有足够的位)是一个编译时常量,所以我把它计算为一个。
然后我根据该决定构建一个类型(std::true_type
或std::false_type
),并调度到两个不同的重载之一。
所以N
太大而无法移动那么远的代码永远不会被实例化,因此没有警告。如果决策中存在逻辑错误,并且代码被实例化,我会收到编译器警告而不是静音(如果您设法禁用警告,并且您遇到逻辑错误,那么您将获得静默UB)。