简体   繁体   English

C ++ 11类型检查代码的奇怪编译器警告

[英]strange compiler warnings of C++11 Type checking code

I'm writing a generic adder with carry/overflow check and I make heavy use of c++11 type check features. 我正在编写带有进位/溢出检查的通用加法器,并且大量使用了c ++ 11类型检查功能。

this is my code: 这是我的代码:

#include <iostream>
using namespace std;
#define MIN_OF(TYPE) ( (std::is_signed<decltype(res)>::value) ? \
                                (1 << ( ( sizeof(decltype(res)) * 8 ) - 1)) : \
                                0 )

#define MAX_OF(TYPE) (~MIN_OF(TYPE))


#define ABS(x)  (x < 0 ? -x : x)

class Flags
{
public:
    void setSign(bool x)
    {
        cout << boolalpha;
        cout << "setSign: " << x << endl;
    }
    void setOverflow(bool x)
    {
        cout << boolalpha;
        cout << "setOverflow: " << x << endl;
    }
    void setCarry(bool x)
    {
        cout << boolalpha;
        cout << "setCarry: " << x << endl;
    }
    void setZero(bool x)
    {
        cout << boolalpha;
        cout << "setZero: " << x << endl;
    }
};

template <typename TYPE, TYPE def>
class Value
{
public:
static inline TYPE get()
{
    return def;
}
static inline void set(TYPE x)
{
    cout << "value: " << hex << x << endl;
}
};


template <class A, class B, class RES>
struct ADD
{
static void Do(Flags* _flags)
{
    if (std::is_convertible<decltype(A::get()),decltype(RES::get())>::value)
    {
        decltype(A::get()) _a = A::get();
        decltype(B::get()) _b = B::get();

        decltype(RES::get()) res = _a;

        if (_b != 0)
        {
            res = res + _b;

            if (std::is_signed<decltype(res)>::value)
            {
                unsigned char highestbit_a = static_cast<unsigned char>(0x1 & (_a >> (( sizeof(decltype(_a)) * 8 ) - 1)));
                unsigned char highestbit_b = static_cast<unsigned char>(0x1 & (_b >> (( sizeof(decltype(_b)) * 8 ) - 1)));
                unsigned char highestbit_res = static_cast<unsigned char>(0x1 & (res >> (( sizeof(decltype(res)) * 8 ) - 1)));

                _flags->setSign( (res < 0) );
                _flags->setOverflow( ((highestbit_a & highestbit_b) != highestbit_res) );
            }
            else
            {
                _flags->setSign( false );
                _flags->setOverflow( false );
            }

            bool setCarryFlag = false;

            if (std::is_signed<decltype(_b)>::value)
            {
                if(_b < 0)
                {
                    /* as _b is negative, we add _b to lowest_res, if the result
                     *  is greater as _a, _a + _b (with _b as negative number) would
                     * result in an carry out
                     */
                    setCarryFlag = (static_cast<decltype(_a)>(ABS((MIN_OF(decltype(res)) - _b))) > _a);
                }
                else
                {
                    setCarryFlag = (static_cast<decltype(_a)>((MAX_OF(decltype(res)) - _b)) < _a);
                }
            }
            else
            {
                //get difference of one summand to results highest until carry
                /* MARKED LINE: this branch gets wrongly checked */
                setCarryFlag = ((MAX_OF(decltype(res)) - _b) < _a);
            }

            _flags->setCarry( setCarryFlag );
        }
        else
        {
            if (std::is_signed<decltype(res)>::value)
            {
                _flags->setSign( (res < 0) );
            }
        }

        _flags->setZero( (res == 0) );

        //store result
        RES::set(res);
    }
}
};



int main()
{
Flags* f = new Flags();
ADD<Value<unsigned int, 1>, Value<signed int, 6>, Value<unsigned int, 1>>::Do(f);

return 0;
}

The problem occurs at the "MARKED LINE: ". 该问题发生在“ MARKED LINE:”。 Normally, I would understand that the compiler wont use this branch, as _b is type of signed int and so is_signed should be true, so the compiler should only use whats in the if-branch and throw away the else branch. 通常,我会理解编译器不会使用此分支,因为_b是有符号int的类型,因此is_signed应该为true,因此编译器应仅在if分支中使用whats并丢弃else分支。 But it doesnt seem to do this, as I get the warning: 但它似乎没有这样做,因为我得到警告:

 warning: comparison between signed and unsigned integer expressions [-Wsign-compare]|

Pointed to this line. 指向这一行。 But this is not what i want. 但这不是我想要的。 Any Ideas how to tell the compiler to do the right thing? 任何想法如何告诉编译器做正确的事情?

comiler is: gcc 4.7.2 on x86-64, debian 编译器是:x86-64上的gcc 4.7.2,debian

Thanks! 谢谢!

It is a warning, not an error. 这是警告,不是错误。 Warnings are there to warn you about things that you likely do not want to do, but are llegal. 警告会警告您一些您可能不想做但违法的事情。 In this case you want to do it, so ignore it. 在这种情况下,您要这样做,因此请忽略它。 You could use a pragma to ignore the warning, however I would recomend documenting how you know it is safe for future devs. 您可以使用编译指示来忽略该警告,但是我建议您记录一下如何知道它对将来的开发人员是安全的。

The GCC specific pragmas to disable this warning are: 禁用此警告的特定于GCC的编译指示为:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
setCarryFlag = ((MAX_OF(decltype(res)) - _b) < _a);
#pragma GCC diagnostic pop

The problem here is the compiler is compiling all the code, even that which will become dead code, because it doesn't know any better. 这里的问题是编译器正在编译所有代码,即使那些将变成死代码的代码,因为它没有更好的了解。

The classic solution is, I believe, to provide another template parameter which has a default value of std::is_signed<B::get()>::value , and then specialize on that parameter *. 我认为,经典的解决方案是 提供另一个模板参数,该参数的默认值为 std::is_signed<B::get()>::value ,然后专门处理该参数 *。 But since you're testing signed-ness for two of your parameters, that's going to get complicated. 但是,由于您要测试两个参数的签名,因此情况将变得复杂。

Another option may simply be to create a signed variable inside the if condition and use that. 另一个选择可能只是在if条件内创建一个带符号的变量并使用它。 That will simply bypass the warning. 这将简单地绕过警告。

if (std::is_signed<decltype(res)>::value) {
    typename std::make_signed<decltype(res)>::type sres = res;
    // now use sres
}

*Xeo reminds me that you can't partially specialize function templates, so the classic solution is actually tag dispatching. * Xeo提醒我您不能对功能模板进行部分专业化,因此经典的解决方案实际上是标签分派。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM