【问题标题】:Fixing "comparison is always false ..." warning in GCC修复 GCC 中的“比较总是错误的......”警告
【发布时间】:2010-06-29 11:06:40
【问题描述】:

我遇到了一个问题,我确信它很容易解决,但我不知所措......

我有一个执行以下代码的模板:

T value     = d;
if ( std::numeric_limits< T >::is_signed )
{
    if ( value < 0 )
    {
        *this += _T( "-" );
        value = -(signed)value;
    }
}

现在,出于显而易见的原因,当此代码针对无符号类型编译时,GCC 会向我发出警告(由于数据类型的范围有限,比较总是错误的)。我完全理解这背后的原因,我进行了 numeric_limits 检查,看看我是否可以让编译器闭嘴(它适用于 MSVC)。唉,在 GCC 下我得到了警告。有什么办法(除了禁用我什至不知道你是否可以用 GCC 做的警告)来修复这个警告吗?无论如何,代码永远不会被调用,我认为优化器也会将其编译出来,但我无法摆脱警告。

谁能给我一个解决方案?

干杯!

【问题讨论】:

  • int 是 16 位时,这是非常讨厌的。当value 是长整数时,value = -(signed /*int*/) value 会截断较大的值。而是乘以-1,然后让优化器算出来。

标签: c++ templates gcc-warning


【解决方案1】:

更简单的解决方案:

template <typename T> inline bool isNegative(T value) {
  return std::numeric_limits< T >::is_signed && value < 0; // Doesn't trigger warning.
}

T value     = d;
if ( isNegative(value) ) // Doesn't trigger warning either.
{
    *this += _T( "-" );
    value = -1 * value;
}

【讨论】:

  • 不幸的是,虽然这修复了 gcc 上的警告,但它在 MSVC 上引入了一个新警告,因为 isNegative 在使用无符号类型 (warning C4100: 'value' : unreferenced formal parameter) 调用时从不使用参数 value。取悦每个编译器是困难的——禁用警告可能比编写在任何地方都能干净编译的代码更好。
  • 扩展到那个;我认为您找到的每个解决方案要么会导致编译器警告,要么会包含更难以维护的复杂逻辑。
  • 我想将 std::numeric_limits&lt;T&gt;::is_signed 包装在函数模板中可能会删除警告:template&lt;typename T&gt; bool is_signed(const T&amp;){return std::numeric_limits&lt;T&gt;::is_signed;} - 但是,如果这样做,它(作为 MSalters 的版本)会这样做 代价在运行时检查中打开编译时检查。最后,我可能会在违规行之前关闭 VC(#pragma warn(push : 4100),IIRC)中的警告,然后再将其重新打开(#pragma warn(pop))。
  • @sbi:我的只是理论上的运行时检查。在你的脑海中进行模板实例化,看看它是如何失败的;你最终得到false &amp;&amp; (unsigned)value &lt; 0true &amp;&amp; (signed)value &lt; 0。显然后者有一个必要的运行时组件。
  • @Joe: 把它改成return value &lt; 0 &amp;&amp; std::numeric_limits&lt; T &gt;::is_signed; 有帮助吗?
【解决方案2】:

谁能给我一个解决方案?

没有什么革命性的,但我通常通过重载来做到这一点。类似的东西:

//Beware, brain-compiled code ahead!
template< bool B >
struct Bool { const static bool result = B; }

template< typename T >
void do_it(T& , Bool<false> /*is_signed*/)
{
  // nothing to do for unsigned types
}

template< typename T >
void do_it(T& value, Bool<true> /*is_signed*/)
{
    if ( value < 0 ) {
        *this += _T( "-" );
        value = -(signed)value;
    }
}

template< typename T >
void do_something(T& value)
{
  do_it(value, Bool<std::numeric_limits< T >::is_signed>() );
}

如果您可以使用类模板而不是函数模板,那么您可以使用特化而不是重载。 (没有函数模板部分特化,这使得特化函数模板有点麻烦。)

【讨论】:

  • 有点过于复杂 - 在 bool 周围引入一个编译时包装器和一个额外的调用参数?此外,value 需要通过非常量引用传递,因为它的值会发生变化。由于它使用了thisT 可能是类的模板参数,而不是函数。
  • 当我发表评论时,您的解决方案无法编译,因为您使用 const 引用作为变异值。如果您将其解释为我对您“生气”,我很抱歉。您可能还注意到我没有否决您的答案。我对评论所做的修改是添加最后一句话。
  • @Joe:那我一定是误读了你的评论,我为我的回复道歉。我删除了我的评论。 (你的评论与后来被证明是被删除的赞成票相吻合,顺便说一句,起初我认为这是反对票。)无论如何,关于Bool&lt;&gt; 类型:我不会梦想没有尝试编写 C++在我的工具箱里。它总是在那里,我只需要在需要时抓住它。 :)
  • 这也是我会做的。这很容易,而且似乎是最有效的方法。我认为您需要交换 truefalse 并修复包装模板的静态常量中的语法。
  • @Johannes:感谢您指出这些脑残。 &lt;sigh&gt; 至少我已经有了标准的免责声明...
【解决方案3】:

有关真正的解决方案,请参阅https://stackoverflow.com/a/8658004/274937,它允许逐个抑制 -Wtype-limits 警告。简而言之,只需将生成警告的每个比较包装到一个虚拟函数中。

【讨论】:

    【解决方案4】:

    您可以像这样专门化您的功能:

    template <bool S> 
    void manipulate_sign(T&) {}
    
    template <> 
    void manipulate_sign<true>(T& value) {
      if ( value < 0 )
      {
        *this += _T( "-" );
        value = -(signed)value;
      }
    }
    
    //then call like this:
    manipulate_sign<std::numeric_limits< T >::is_signed>();
    

    只是禁用警告可能会更好。

    【讨论】:

    • 我肯定会封装这个函数,这样用户就不必自己使用numeric_limits - T 是函数需要的所有信息:)
    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多