如何删除由于正确的流动分支而永远不会发生的负移位警告?

时间:2014-11-05 09:32:20

标签: c++ templates

在使用模板编译某些代码时,我遇到了一些非常有趣的错误。

问题是编译器似乎无法比较数字。它会警告一个参数是大于还是小。

我的最小例子如下:

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我的单元测试工作正常,但在编译我的代码时我宁愿没有警告。

2 个答案:

答案 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)

即使shiftotherShift是模板参数:

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; };