为什么 gcc 警告只针对统一初始化缩小转换范围?

Why gcc warns about narrowing conversion only for uniform initialization?

本文关键字:缩小 初始化 转换 范围 警告 gcc 为什么      更新时间:2023-10-16

我正在尝试将long类型变量转换为int带有uniform initialization和没有它的类型变量。但是我只在统一初始化时收到编译器警告。为什么?为什么gcc在这两种情况下都不警告?我也尝试过clang,并得到了类似的结果。

这是代码

#include <iostream>
int main() {
long l = 1;
int i1 = l;
int i2 = { l };
std::cout << i1 << std::endl;
std::cout << i2 << std::endl;
return 0;
}

也是我收到的唯一一个警告

$ g++ -Wall -Wextra 1.cpp
1.cpp: In function ‘int main()’:
1.cpp:6:16: warning: narrowing conversion of ‘l’ from ‘long int’ to ‘int’ inside { } [-Wnarrowing]
int i2 = { l };

因为标准说,缩小转换限制只为列表初始化指定(自 C++11 起)。

列表初始化通过以下方式限制允许的隐式转换 禁止以下行为:

  • 从浮点类型转换为整数类型
  • 从长双精度转换为双精度或浮点
  • 数以及从双精度到浮点数的转换,除非源是常量表达式 并且不会发生溢出
  • 从整数类型转换为浮点类型,除非源是可以存储其值的常量表达式 完全在目标类型中
  • 从整数或无作用域枚举类型转换为不能表示原始值的所有值的整数类型,源除外 是一个常量表达式,其值可以精确地存储在 目标类型

对于其他初始化方法(使用括号或等号),不应用(添加)缩小转换限制规则;因为这可能会破坏许多遗留代码。

两者之间的区别在于,在列表初始化中不允许缩小转换范围。在其他形式的初始化中,它们是允许的。

这里经常让人们感到困惑的是,当某些事情不允许时,并不意味着编译器必须拒绝编译代码。要求是编译器必须"发出诊断",警告是一种有效的诊断形式。

因此,编译器需要为列表初始化中的缩小转换发出诊断,这就是您所看到的。除此之外,正如其他人所说,您可以提高警告级别,以获取有关在其他情况下缩小转化范围的警告。但是在列表初始化之外,诊断不是必需的,而且它们通常比有用更烦人,因此默认情况下不打开。