使用花括号从double初始化float

8
为什么编译器(clang,gcc)在进行此操作时不会警告缩小转换?
float a{3.1231231241234123512354123512341235123541235};
float a = {double(3.1231231241234123512354123512341235123541235)}

我原本预计会收到警告,因为我使用大括号进行显式的值初始化。 根据这个答案 链接 ,它应该会报错。

这里是编译结果


3
据我所知,它不会警告你特定的文字值是否可以以更窄的类型表示而不会失去精度。 - Piotr Skotnicki
这在VS2015上无法编译(错误2397)。 - Fefux
2个回答

15

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

窄化转换是一种隐式转换

...

  • 从 long double 到 double 或 float,或从 double 到 float,但当源是一个常量表达式且实际值在可表示的值范围内(即使不能完全表示)时,不属于窄化转换,或者

...

表达式 3.14159double(3.141) 都是常量表达式,且其值在可以被 float 表示的范围内。因此,根据标准所定义的窄化转换,这种转换不属于窄化,也就没有必要对其进行警告。


但是长输入的情况下也没有警告

确实会有警告,只要该值超出了 float 可表示的范围。


10
因为源代码是一个常量表达式,并且在这些情况下不会发生溢出,所以缩小转换错误不会触发。(强调我的)
将长双精度浮点数转换为双精度或浮点数,以及将双精度转换为浮点数,除非源是一个常量表达式且不发生溢出。
如果您将其与double变量(即非常量表达式)或具有大值的常量一起使用,将生成诊断消息。 例如:
double d = 3.14159;
float a {d}; // non-constant-expression cannot be narrowed from type 'double' to 'float' in initializer list

编辑(适用于较长的输入)

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

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

从长双精度转换为双精度或浮点数,或从双精度转换为浮点数,除非源是常量表达式并且转换后的实际值在可以表示的值范围内(即使不能精确表示),或者


1
当你说“应该是一个错误,而不是一个警告”时,我想澄清的是标准并不要求它成为一个错误。 - eerorika
@user2079303 标准规定“不允许进行这样的转换”,所以我认为不需要警告,对吗? - songyuanyao
1
@songyuanyao 标准规定:“如果需要缩小转换(见下文)来转换任何参数,则程序是不合法的”。标准的其他地方也指出,如果程序不合法,编译器必须显示诊断消息。除此之外,没有其他要求,比如该消息是否为错误消息以及是否会阻止编译。 - eerorika
1
@Gabriel,看看我的编辑后的答案(如果我理解你的意思正确的话)。 - songyuanyao
1
@songyuanyao 在第7点的注释中,开头写着“如上所示”,这指的是我引用的规则。我认为它只是对规则的提醒,而不是一条优先规则。话虽如此,我认为这没有任何影响。我不认为标准在任何时候要求编译必须失败。当一个程序违反了标准,它是不合法的(除非另有规定,例如存在未定义行为),并且必须有一条消息。标准从未规定消息是否为错误,这取决于编译器是否允许编译。 - eerorika
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接