如果第一个操作数是常量表达式,则为"?:"的类型

a.l*_*ram 15 c++ c++11

请考虑以下代码:

void f(float x)
{
    x * (true ? 1.f : 0.0);
}
Run Code Online (Sandbox Code Playgroud)

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

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

void f(float x)
{
    double(x) * 1.0;
} 
Run Code Online (Sandbox Code Playgroud)

或者是否有一个语句允许在第一个操作数?:是编译时常量表达式的情况下进行优化?

sas*_*hka 14

是的,它确实意味着上述代码是等效的.

使用RTTI,我们可以检查至少两个clang并且g++符合标准并给出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;
}
Run Code Online (Sandbox Code Playgroud)

以及使用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;
}
Run Code Online (Sandbox Code Playgroud)

输出true.


ric*_*ici 10

C++编译器可以根据需要进行优化,前提是它不会改变符合程序的"可观察行为"(§1.9p1,即所谓的"仿佛"规则).

例如,如果在给定平台上已知乘以1.0是不具有陷阱潜力的身份转换,则实际上不需要执行乘法.(对于给定的体系结构,这可能也可能不是这样,因为将NaN值乘以1.0可能会陷阱.但是,编译器也可以用在相同情况下产生相同陷阱的任何其他操作替换乘法. .)

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

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