第一个操作数是常量表达式时的'?:'类型

Type of '?:' if the first operand is a constant expression

本文关键字:类型 操作数 常量 表达式 第一个      更新时间:2023-10-16

考虑以下代码:

void f(float x)
{
    x * (true ? 1.f : 0.0);
}

根据C++标准[expr.cond],declval(bool) ? declval(float) : declval(double)的类型是double

这是否意味着上述代码必须等效于:

void f(float x)
{
    double(x) * 1.0;
} 

或者,如果?:的第一个操作数是编译时常数表达式,是否有允许优化的语句?

是的,这确实意味着上述代码是等效的。

使用RTTI,我们可以检查至少clangg++都符合标准,并将d(例如,double)作为该程序的输出:

#include <iostream>
#include <typeinfo>
int main() {
    float x = 3.;
    auto val = x * (true ? 1.f : 0.0);
    std::cout << typeid(val).name() << std::endl;
}

以及使用C++11类型特征的替代方法

#include <iostream>
#include <typeinfo>
int main() {
    float x = 3.;
    auto val = x * (true ? 1.f : 0.0);
    std::cout << std::boolalpha <<
        std::is_same<decltype(val), double>::value << std::endl;
}

输出true

C++编译器可以根据自己的意愿进行优化,前提是它不会改变一致性程序的"可观察行为"(§1.9p1,即所谓的"好像"规则)。

例如,如果在给定的平台上,已知乘以1.0是一种没有陷阱的恒等式变换,那么实际上不需要执行乘法。(对于给定的体系结构,这可能是真的,也可能不是真的,因为将NaN值乘以1.0可能会陷阱。然而,编译器也可以用任何其他操作来代替乘法,这些操作在相同的情况下会产生相同的陷阱。)

在没有陷阱的情况下,假设乘以1.0是一个单位变换,则可以消除函数f的整个主体,因为标准要求float值的集合是double值的集合(可能是同一集合)的子集。因此,float->double->float往返行程必须返回到原始值或陷阱。(§3.9.1p8:"类型float的值集是类型double的值集的子集"。§4.8p1:"浮点类型的prvalue可以转换为另一个浮点类型的pr value。如果源值可以在目标类型中精确表示,则转换的结果就是该精确表示。")

所以,是的,优化是可能的。但这并不影响?:表达式的类型,在该类型是可观察的情况下(例如,如果该表达式用于模板推导或用作decltype的操作数)。

相关文章: