在使用列表初始化构造变量时(比如 int x{ 5 };
),标准 §8.5.4 规定:
如果需要进行缩小转换[...]以转换任何一个参数,则程序是非法的。 (7) 缩小转换是一种隐式转换 - (7.4) 从整数类型或未经作用域限定的枚举类型到整数类型的转换,该整数类型不能表示原始类型的所有值,但源自常量表达式的情况除外,并且在积分提升后其值将适合目标类型。
那么为什么这段代码可以编译通过?
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将'int'转换为'unsigned char'需要进行缩小转换
引入临时变量也是如此:
char c{ 'A' };
int sum{ c + c };
char x{ sum }; //C2397 conversion from 'int' to 'char' requires [...]
那么为什么第一个版本会编译通过呢?我使用的是Visual Studio Community 2017版本15.9.5,使用/wall
编译,并启用所有警告均视为错误,在x64
调试构建中编译。设置标准为C++11、C++14和C++17时都可以编译通过。
我在这里提交了错误报告。