使用双精度的MSVC大括号初始化似乎违反了标准?

时间:2016-07-08 21:17:35

标签: c++ c++11 visual-c++ language-lawyer list-initialization

查看这个简单的程序:

int main() {
    float f2 = 7.2; // OK, with warning
    float f3 = 7.199999809265137; // OK, no warning
    float f4{ 7.2 }; // Fails
    float f5{ 7.199999809265137 }; // OK, no warning
    float f6 = { 7.2 }; // Fails
    float f7 = { 7.199999809265137 }; // OK, no warning
}

使用默认选项(cl /W4,版本19.00.23918)使用MSVC 2015进行编译时,收到以下消息:

FloatTest.cpp(2): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(4): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(4): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(6): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(6): warning C4305: 'initializing': truncation from 'double' to 'float'

该程序与Clang 3.0-3.8和GCC 4.5.4-6.1.0(使用http://melpon.org/wandbox测试)编译良好,仅对未使用的变量发出警告。此外,删除/注释掉行f4f6会导致成功编译(只有行f2的一个警告)。

最初看起来MSVC只是告诉我7.2不能精确地表示为float,所以它是一个缩小的转换(在大括号初始化时是非法的)。但是,标准(draft N3337),第8.5.4节,注释7说明了这一点:

  

缩小转化是隐式转化......

     
      
  • long doubledoublefloat,或从doublefloat,除非源是常量表达式,转换后的实际值除外在可以表示的值范围内(即使它不能完全表示
  •   

强调我的。由于7.2在float可表示的值范围内,因此根据标准,其转换为float不应是缩小转换。 MSVC在这里是错误的,我应该提交错误吗?

2 个答案:

答案 0 :(得分:6)

事实上,它看起来像一个错误。对于解决方法,以下内容似乎可以消除MSVC 2015中的错误和警告。

#pragma float_control(precise, off, push)

float f2 = 7.2; // OK, with warning
//...

#pragma float_control(precise, pop)

如果使用/fp:fast编译器开关,则全局同样有效,尽管该开关与禁用MS语言扩展的/Za不兼容。

答案 1 :(得分:-3)

某些浮点数可以用float表示精确表示,有些则不能。如果数字可以x / 2^y形式表示,其中x是任何整数,而y是23或更小的整数,则它适合。 大多数十进制数不能以这种方式表示,作为二进制数,它们永远重复。 7.2就是一个例子。

您可以通过将f附加到每个数字来轻松解决此问题,以向编译器表明这是float常量,而不是double

float f4{ 7.2f };