Consider the following code:
void f(float x)
{
x * (true ? 1.f : 0.0);
}
The type of declval(bool) ? declval(float) : declval(double)
is double
according to the C++ standard [expr.cond].
Does this mean that the above code has to be equivalent to:
void f(float x)
{
double(x) * 1.0;
}
Or is there a statement that allows an optimization in case the first operand of ?:
is a compile time constant expression ?
A constant expression is an expression that can be evaluated at compile time. Constants of integral or enumerated type are required in several different situations, such as array bounds, enumerator values, and case labels. Null pointer constants are a special case of integral constants.
A constant expression gets evaluated at compile time, not run time, and can be used in any place that a constant can be used. The constant expression must evaluate to a constant that is in the range of representable values for that type.
Yes, it does mean that the above codes are equivalent.
Using RTTI we can check that at least both clang
and g++
are standard conformant and give d
(e.g. double) as an output to this program:
#include <iostream>
#include <typeinfo>
int main() {
float x = 3.;
auto val = x * (true ? 1.f : 0.0);
std::cout << typeid(val).name() << std::endl;
}
And the alternative way using 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;
}
Outputs true
.
A C++ compiler can optimize as it sees fit, provided that it does not alter the "observable behaviour" of a conforming program (§1.9p1, the so-called "as if" rule).
For example, if on a given platform it is known that multiplying by 1.0 is an identity transformation without the potential to trap, then the multiplication does not actually need to be performed. (This may or may not be true for a given architecture, since it is possible that multiplying a NaN value by 1.0 could trap. However, the compiler could also replace the multiplication by any other operation which would produce the same trap under the same circumstances.)
In the absence of traps and assuming that multiplication by 1.0 is an identity transform, the entire body of your function f
can be eliminated, because the standard requires that the set of float
values is a subset of the set of double
values (possibly the same set). Consequently, the float->double->float round trip must return to the original value or trap. (§3.9.1p8: "The set of values of the type float
is a subset of the set of values of the type double
". §4.8p1: "A prvalue of floating point type can be converted to a prvalue of another floating point type. If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation.")
So, yes, optimizations may be possible. But that does not affect the type of the ?:
expression, in the case that the type is observable (for example, if the expression were to be used for template deduction or as the operand of decltype
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With