【问题标题】:C4127: Conditional Expression is ConstantC4127:条件表达式是常数
【发布时间】:2014-08-29 18:17:16
【问题描述】:

以下代码在 Visual Studio 2010 中生成警告 C4127(条件表达式为常量)(其中 alias_wchar_t 是 wchar_t 的别名):

if (sizeof(alias_wchar_t) == sizeof(wchar_t)) // warning occurs here
{
    // do stuff
}
else
{
    // do other stuff
}

除了抑制警告之外,解决这个问题的最优雅的方法是什么?

我想出的最佳解决方案是将条件填充到静态布尔值中,并将其用作条件。 if-else 的上下都有大量的代码,所以我将整个代码都用大括号括起来,以尽可能地限制变量的范围:

// <snip>

{
    static bool isSameSize = (sizeof(alias_wchar_t) == sizeof(wchar_t));
    if (isSameSize)
    {
        // do stuff
    }
    else
    {
        // do other stuff
    }
}

// <snip>

这感觉很恶心。这似乎应该在编译时而不是运行时解决,但预处理器不知道 sizeof。有没有更简洁、更优雅的方法来解决这个问题?

【问题讨论】:

  • 注意:C++17 正在考虑使用类似if constexpr 的方法来解决这个问题

标签: c++ visual-studio-2010 c4127


【解决方案1】:

在 C++17 中,解决方法是使用 if constexpr:

if constexpr (sizeof(alias_wchar_t) == sizeof(wchar_t)) // warning occurs here
{
    // do stuff
}
else
{
    // do other stuff
}

参考:Visual C++ Blog

【讨论】:

    【解决方案2】:

    看起来你知道发生了什么,而且你没问题。

    编译器pragmas 适用于这样的情况:

    __pragma(warning(push))
    __pragma(warning(disable:4127))
    if (sizeof(alias_wchar_t) == sizeof(wchar_t)) {
    __pragma(warning(pop))
    }
    

    本质上,您是在告诉编译器(更重要的是,向代码的人类读者)您已经查看了警告,并且您知道自己在做什么。

    【讨论】:

    • 我个人认为 Christopher Berman 的原始解决方案更好。编译指示是特定于编译器的并且过于冗长。
    【解决方案3】:

    除了抑制 警告?

    条件在编译时是已知的,因此您也可以在编译时进行检查。不要使用if,只需让编译器插入对正确函数的调用即可。这是一个完整的例子:

    #include <iostream>
    
    typedef short alias_wchar_t; // for testing
    
    template<bool Condition>
    struct DoStuff
    {
    };
    
    template<>
    struct DoStuff<true>
    {
        static void doStuff()
        {
            std::cout << "sizeof(alias_wchar_t) == sizeof(wchar_t)\n"; 
        }
    };
    
    template<>
    struct DoStuff<false>
    {
        static void doStuff()
        {
            std::cout << "sizeof(alias_wchar_t) != sizeof(wchar_t)\n"; 
        }
    };
    
    void doStuff()
    {
        DoStuff<sizeof(alias_wchar_t) == sizeof(wchar_t)>::doStuff();
    }
    
    int main()
    {
        doStuff();
    }
    

    我会说,这是否真的比您的原始代码更优雅(仅针对该编译单元关闭了特定的编译器警告)是基于意见的。

    无论如何,在/W4 VC 2013 编译时没有警告。

    【讨论】:

    • 你不认为你只是将要维护的代码量增加了一倍吗?)
    • @AlexanderEnaldiev:代码长度并不是决定某些东西的维护难易程度的唯一因素。正如我两年多前在这里所说,是否更优雅取决于代码的实际上下文。
    • 不能同意你的看法。这可能毫无意义。假设 template struct Foo { bool Check() { bool retval = checkImpl(); if (Strict) retval = retval && checkStrict();返回 retval; } };我这里有 C4127 做什么?你不觉得吗,我很确定常量取决于模板 arg 吗?或者C4127有什么意义。它显示了什么?还是想不通。不管过去多少年;)
    • @AlexanderEnaldiev:我没有得到 C4217。 Visual C++ 2015,/W4(甚至没有/Wall)。话虽如此,它可以变得更优雅,我不介意为此发出警告。您基本上有两个不同的类Foo&lt;true&gt; 和Foo&lt;false&gt;,一个测试true == true,另一个测试true == false。模板专业化在概念上会更清晰。
    • 事实证明你是对的,我错了,-他们从 ~VS2013 开始删除了它。时间在流逝。 (可以通过使用 VS2010 轻松复制,但现在可以将 vs2010 视为遗留编译器(例如,关于 C++0x、C++0y 功能支持)。
    【解决方案4】:

    另一种禁用警告的方法是创建一个虚拟标识函数并将其用于其中一个常量。

    // Define this somewhere
    template<typename T> const T& identity(const T& t) { return t; }
    
    ...
    
    // NB: 'identity' used only to remove "warning C4127"
    if (identity(sizeof(alias_wchar_t)) == sizeof(wchar_t))
    {
        // do stuff
    }
    else
    {
        // do other stuff
    }
    

    这并不完美,但似乎比其他解决方案更轻量级,并且可重复用于不同类型的常量。

    【讨论】:

      【解决方案5】:

      这是我想出的。它不会在 Microsoft Visual Studio 2013 中引起任何警告,也不需要您使用 Visual C++ 特定的编译指示。

      首先定义如下模板类。

      template <bool b>
      struct condition
      {
          static bool test()
          {
              return true;
          }
      };
      template <>
      struct condition<false>
      {
          static bool test()
          {
              return false;
          }
      };
      

      然后如下使用。

      if (condition<sizeof(alias_wchar_t) == sizeof(wchar_t)>::test())
      

      我从 http://en.cppreference.com/w/cpp/types/conditional 描述的 C++14 std::conditional 中得到了这个想法。

      【讨论】:

        【解决方案6】:

        如果它只是一个常量表达式,那么使用:

        typedef wchar_t alias_wchar_t;
        bool constExpression = sizeof(alias_wchar_t) == sizeof(wchar_t);
        if (constExpression) // potential warning
        {
            // do stuff
        }
        else
        {
            // do other stuff
        }
        

        看来 c4127 是通过评估控制语句中的常量表达式而生成的。

        【讨论】:

        • 我成功地使用了这个变体: constexpr bool constExpression = sizeof(alias_wchar_t) == sizeof(wchar_t); if (constExpression) {}
        • 这对我不起作用,使用 VS2012 编译器。在“if”语句中仍然收到相同的警告。
        猜你喜欢
        • 2015-08-31
        • 2015-05-13
        • 1970-01-01
        • 1970-01-01
        • 2014-05-16
        • 1970-01-01
        • 2017-03-30
        • 2010-09-18
        • 1970-01-01
        相关资源
        最近更新 更多