15

考虑以下代码:

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

declval(bool) ? declval(float) : declval(double)的类型double符合 C++ 标准 [expr.cond]。

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

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

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

4

2 回答 2

14

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

使用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

于 2013-06-22T20:51:26.620 回答
10

C++ 编译器可以按照它认为合适的方式进行优化,前提是它不会改变符合程序的“可观察行为”(§1.9p1,所谓的“好像”规则)。

例如,如果在给定的平台上,已知乘以 1.0 是一个恒等变换,没有陷阱的可能性,则实际上不需要执行乘法。(对于给定的体系结构,这可能正确,也可能不正确,因为将 NaN 值乘以 1.0 可能会陷入陷阱。但是,编译器也可以将乘法替换为在相同情况下会产生相同陷阱的任何其他操作.)

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

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

于 2013-06-22T22:15:45.160 回答