【问题标题】:float initialization from double with braces用大括号从双精度浮点初始化
【发布时间】:2016-11-25 13:10:44
【问题描述】:

为什么编译器(clang,gcc)在执行此操作时不警告缩小转换

float a{3.1231231241234123512354123512341235123541235};
float a = {double(3.1231231241234123512354123512341235123541235)}

我预计会收到警告,因为我使用大括号进行了显式值初始化。 按照这个答案Link 它应该会吐出一个错误。

Compilation here

【问题讨论】:

  • afaik,它不会警告您是否可以在不损失精度的情况下以更窄的类型表示特定的文字值
  • 这不能在 VS2015 上编译(错误 2397)

标签: c++ c++11 c++14 list-initialization value-initialization


【解决方案1】:

[dcl.init.list]/§7(标准草案)

窄化转换是隐式转换

...

  • 从long double到double或者float,或者从double到float,除非源是常量表达式,并且转换后的实际值在可以表示的值范围内(即使不能表示准确表示),或

...

表达式3.14159double(3.141) 都是常量表达式,其值在float 可表示的值范围内。因此,转换不是标准定义的缩小范围,也不需要警告转换。


但对于较长的输入也不会发出警告

Sure it does,只要该值超出float 可表示的值范围即可。

【讨论】:

    【解决方案2】:

    由于源是常量表达式,这些情况不会发生溢出,所以不会触发narrowing conversion错误。

    (强调我的)

    从 long double 转换为 double 或 float 以及从 double 转换为 float,源为常量表达式且不会发生溢出的情况除外

    如果您将其与double 变量(即非常量表达式)或导致溢出的大值常量一起使用,将生成诊断消息。例如

    double d = 3.14159;
    float a {d}; // non-constant-expression cannot be narrowed from type 'double' to 'float' in initializer list
    

    EDIT(用于更长的输入)

    因为即使值不能用float精确表示,也不会发生溢出,所以是允许的。

    $8.6.4/7.2 List-initialization (强调我的)

    从long double到double或者float,或者从double到float,除非源是常量表达式且转换后的实际值在可以表示的值范围内(即使不能表示准确表示),或

    【讨论】:

    • 当你说应该是一个错误,而不是一个警告,我会澄清标准并不要求这是一个错误。
    • @user2079303 标准说“不允许这样的转换”,所以我认为警告不是这样的,不是吗?
    • @songyuanyao 标准说“如果需要缩小转换(见下文)来转换任何参数,则程序是格式错误”。在标准的其他地方,它说如果程序格式错误,编译器需要显示诊断消息。没有其他要求,例如消息是错误并阻止编译。
    • @Gabriel 查看我编辑的答案,(如果我理解正确的话)。
    • @songyuanyao #7中的注释以“如上所述”开头,指的是我引用的规则。我认为这只是对规则的提醒,而不是压倒一切的规则。也就是说,我认为这没有任何区别。我不认为标准在任何时候都要求编译必须失败。当一个程序违反标准时,它是格式错误的(除非另有说明,例如当有 UB 时),并且必须有一条消息。标准从未指定消息是否为错误,编译器可以自行决定是否允许编译。
    猜你喜欢
    • 2017-07-24
    • 2015-06-04
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多