为什么未检测到这种缩小转换?

Why is this narrowing conversion not detected?

使用列表初始化构造变量时(如 int x{ 5 };the standard §8.5.4 说:

If a narrowing conversion […] is required to convert any of the arguments, the program is ill-formed. (7) A narrowing conversion is an implicit conversion - (7.4) from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.

那么为什么会编译?

char c{ 'A' };
char x{ c + c };

提醒一下,c + c 会产生 int

static_assert(std::is_same_v<decltype(c + c), int>, "");

所以编译器应该抱怨一个肯定不是常量表达式的窄化转换。


有趣的是,将 x 声明为 unsigned char 正确编译失败:

char c{ 'A' };
unsigned char x{ c + c }; 

C2397 conversion from 'int' to 'unsigned char' requires a narrowing conversion

与引入临时对象一样:

char c{ 'A' };
int sum{ c + c };
char x{ sum }; //C2397 conversion from 'int' to 'char' requires [...]

那么为什么第一个版本可以编译?我正在使用 Visual Studio 社区 2017 版本 15.9.5 并使用 /wall 编译它,所有警告都是在 x64 调试版本中启用的错误。设置标准 C++11、C++14 和 C++17 都可以编译。


我提交了错误报告 here

是的。你是对的:程序是ill-formed.

在这种情况下(标准§1.4):

a conforming implementation shall issue at least one diagnostic message.

的确,gcc 产生了一条警告消息。 clang 直接拒绝代码作为编译器错误。

此特定主题已针对 gcc1.

进行了讨论 here

Visual Studio 应该会产生一条诊断消息(我建议您检查您的编译选项。您是否禁用了警告?您是否使用 C++(11/14/17)?, ...)。如果不是这种情况,则为实现错误。

更新:

Visual Studio v19.20 不会产生任何诊断消息(即使带有 /Wall 标志)。

A bug report这里已经填好了


1 有关缩小检查的 gcc 实现的更多信息 here