不,真的,浮点提升什么时候发生?

No really, when does floating point promotion actually happen?

从另一个 QUESTION 他们谈论 Bjarne Stroustrup 是如何说的,就像比 int(例如 short)窄的整数数据类型被提升为 intfloat 被提升为 double。然而,与扩大比 int 更窄的积分不同, 浮点提升 不会以相同的方式发生,而是发生别处。

我知道,如果您要计算 float + double,则 float 会在应用二元运算符 (+) 之前转换为 double。然而,根据Learncpp.com,这不是浮点提升。这是普通算术转换.

浮点提升实际发生在什么时候?

应用浮点提升的主要(可能唯一)时间是将参数传递给可变参数函数(例如,printf)。

在这种情况下,通常的算术转换不适用(它们用于查找表达式中两个操作数之间的公共类型)。

标准的相关部分是 [expr.call]/7(至少从 N4296 开始):

When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.10).
[...]
If the argument has integral or enumeration type that is subject to the integral promotions (4.5), or a floating point type that is subject to the floating point promotion (4.6), the value of the argument is converted to the promoted type before the call.

每个 [conv.fpprom].

中有 floatdouble 这样的事情

A prvalue of type float can be converted to a prvalue of type double. The value is unchanged.

This conversion is called floating point promotion.

链接问题的答案是正确的。添加两个 float 时不应自动进行此提升,因为通常的算术转换不会提升浮点操作数。

当将 float 作为操作数传递给省略号时, 会发生浮点数提升,例如 printf。这就是 %f 格式说明符打印 floatdouble 的原因:如果您传递 float,函数实际上接收 double,结果促销。

浮点数提升的存在在重载决策中也很重要,因为整数promotions和浮点数promotions有更好的隐式转换排名高于积分 conversions、浮点 conversions 和浮点积分 conversions.

示例 1:

void f(double);
void f(long double);
f(0.0f);

这会调用 void f(double),因为升级到 double 比转换到 long double 更好。相比之下,请考虑这个可能令人惊讶的示例 2:

void f(long double);
void f(int);
f(0.0f);

这是模棱两可的。从 floatlong double 的转换并不比从 floatint 的转换好,因为它们都不是促销。

示例 3:

struct S {
    operator float();
    operator int();
};
double d = S();

这会调用 operator float,然后将生成的 float 值提升为 double 以初始化 d