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

Why gcc warns about narrowing conversion only for uniform initialization?

我正在尝试将 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 };

因为标准说,narrowing conversions limit 仅指定用于列表初始化(C++11 起)。

list-initialization limits the allowed implicit conversions by prohibiting the following:

  • conversion from a floating-point type to an integer type
  • conversion from a long double to double or to float and conversion from double to float, except where the source is a constant expression and overflow does not occur
  • conversion from an integer type to a floating-point type, except where the source is a constant expression whose value can be stored exactly in the target type
  • conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where source is a constant expression whose value can be stored exactly in the target type

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

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

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

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