【问题标题】:Why gcc warns about narrowing conversion only for uniform initialization?为什么 gcc 仅针对统一初始化警告缩小转换?
【发布时间】:2018-12-31 23:40:03
【问题描述】:

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

【问题讨论】:

  • 因为这是指定语言的工作方式?
  • 这只是为了向后兼容而保留的语言缺陷之一。
  • 编译器(几乎)没有义务发出警告。将警告视为帮手,但不要依赖编译器总是警告有问题的构造或错误代码。最后,您有责任了解语言规则并编写正确的代码。编译器只是在可能的时候(通常)尝试提供帮助。至于缩小转换;只有在使用“{}”语法时才允许这些。
  • 使用-Wconversion 获得更多转化警告。
  • @JesperJuhl 更准确地说:当程序格式错误时(例如在示例的第三次初始化的情况下),编译器(几乎)总是有义务发出诊断消息。但是,如果编译器选择拒绝编译格式错误的程序(这是允许的,但不是强制的),则诊断消息通俗地归类为错误,而不是警告。编译器没有义务警告格式正确的代码,例如前两个初始化。

标签: c++ c++11 language-lawyer compiler-warnings uniform-initialization


【解决方案1】:

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

list-initialization 通过以下方式限制允许的隐式转换 禁止:

  • 从浮点类型转换为整数类型
  • 从 long double 到 double 或到 float 的转换以及从 double 到 float 的转换,除非源是常量表达式 并且不会发生溢出
  • 从整数类型转换为浮点类型,除非源是可以存储其值的常量表达式 完全符合目标类型
  • 从整数或无范围枚举类型转换为不能表示原始值的所有值的整数类型,除非源 是一个常量表达式,其值可以精确地存储在 目标类型

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

【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2016-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2011-12-05
    • 2014-01-29
    相关资源
    最近更新 更多