Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

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 ?

like image 718
a.lasram Avatar asked Jun 22 '13 20:06

a.lasram


People also ask

What is a 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.

What is a constant expression in C?

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.


2 Answers

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.

like image 126
sasha.sochka Avatar answered Sep 29 '22 11:09

sasha.sochka


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).

like image 43
rici Avatar answered Sep 29 '22 11:09

rici