C4127:条件表达式是常数
Posted
技术标签:
【中文标题】C4127:条件表达式是常数【英文标题】:C4127: Conditional Expression is Constant 【发布时间】: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
的方法来解决这个问题
【参考方案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】:看起来你知道发生了什么,而且你没问题。
编译器pragma
s 适用于这样的情况:
__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/W4
(甚至没有/Wall
)。话虽如此,它可以变得更优雅,我不介意为此发出警告。您基本上有两个不同的类Foo<true>
和Foo<false>
,一个测试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”语句中仍然收到相同的警告。以上是关于C4127:条件表达式是常数的主要内容,如果未能解决你的问题,请参考以下文章