在使用模板编译某些代码时,我遇到了一些非常有趣的错误。
问题是编译器似乎无法比较数字。它会警告一个参数是大于还是小。
我的最小例子如下:
template< int shift >
struct Shifter
{
int value;
template< int otherShift >
Shifter< shift > &operator >>=( Shifter< otherShift > &rhs )
{
if ( shift > otherShift )
{
this->value = rhs.value >> (shift - otherShift);
return *this;
}
else
{
this->value = rhs.value << (otherShift - shift );
return *this;
}
}
};
int main( void )
{
Shifter< 3U > a = { 5 };
Shifter< 2U > b = { 2 };
a >>= b;
b >>= a;
}
编译时,我收到以下警告:
In instantiation of 'Shifter<shift>& Shifter<shift>::operator>>=(Shifter<otherShift>&) [with int otherShift = 2; int shift = 3 ]'
warning: left shift by negative number [enabled by default]
In instantiation of 'Shifter<shift>& Shifter<shift>::operator>>=(Shifter<otherShift>&) [with int otherShift = 3; int shift = 2 ]'
warning: right shift by negative number [enabled by default]
警告信息是从丹麦语中翻译出来的,因此可能不是逐字的。
编译器是Windows上的minGW gcc 4.7.2以及来自IAR的iccarm
我真的需要使用c ++ 03而不使用boost,所以请不要使用enable_if或“只使用boost-this-and-that”答案。
BTW我的单元测试工作正常,但在编译我的代码时我宁愿没有警告。
答案 0 :(得分:2)
问题是,编译器没有检查if子句,因此无法知道你是否执行负移位。
您可以使用绝对功能来避免这种情况:
#include <cstdlib>
// ...
template< int otherShift >
Shifter< shift > &operator >>=( Shifter< otherShift > &rhs )
{
if ( shift > otherShift )
{
this->value = rhs.value >> abs(shift - otherShift);
return *this;
}
else
{
this->value = rhs.value << abs(otherShift - shift );
return *this;
}
答案 1 :(得分:1)
即使shift
和otherShift
是模板参数:
if (shift > otherShift) {
this->value = rhs.value >> (shift - otherShift);
return *this;
} else {
this->value = rhs.value << (otherShift - shift );
return *this;
}
编译器必须评估所有分支(因此分支应该有效)。
因此,即使您确保根据(shift - otherShift
)的符号调用正确的班次,另一个(死)分支也会产生警告。
您可以使用SFINAE:
template< int otherShift >
typename std::enable_if<(shift > otherShift), Shifter<shift> >::type
&operator >>=( Shifter< otherShift > &rhs )
{
this->value = rhs.value >> (shift - otherShift);
return *this;
}
template< int otherShift >
typename std::enable_if<(shift <= otherShift), Shifter<shift> >::type
&operator >>=( Shifter< otherShift > &rhs )
{
this->value = rhs.value << (otherShift - shift );
return *this;
}
使用C ++ 03,您可以定义自己的enable_if
:
template<bool Cond, class T = void> struct enable_if {};
template<class T> struct enable_if<true, T> { typedef T type; };