请考虑以下代码:
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;
}
或者是否有一个语句允许在?:
的第一个操作数是编译时常量表达式的情况下进行优化?
答案 0 :(得分: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;
}
使用C ++ 11 type traits
的替代方法#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
。
答案 1 :(得分:10)
C ++编译器可以根据需要进行优化,前提是它不会改变符合程序的“可观察行为”(§1.9p1,即所谓的“仿佛”规则)。
例如,如果在给定平台上已知乘以1.0是不具有陷阱潜力的身份转换,则实际上不需要执行乘法。 (对于给定的体系结构,这可能也可能不是这样,因为将NaN值乘以1.0可能会陷阱。但是,编译器也可以用在相同情况下产生相同陷阱的任何其他操作替换乘法。 。)
如果没有陷阱并且假设乘以1.0是一个恒等变换,则可以消除函数f
的整个主体,因为标准要求float
值的集合是double
值集的子集(可能是相同的集合)。因此,float-&gt; double-&gt; float往返必须返回原始值或陷阱。 (§3.9.1p8:“类型float
的值集合是double
类型值集合的子集”.§4.8p1:“浮点类型的prvalue可以是转换为另一个浮点类型的prvalue。如果源值可以在目标类型中准确表示,则转换的结果就是精确表示。“)
所以,是的,优化可能是可能的。但是,在类型是可观察的情况下(例如,如果表达式用于模板推导或作为?:
的操作数),这不会影响decltype
表达式的类型。