user3020233
user3020233

Reputation: 327

How is this boolean expression evaluated?

In C++, let the following construct :

template<typename ValueType>
ValueType * func(Foo * foo)
{
    Bar bar;
    return foo && typeid(foo) == typeid(ValueType) ? &static_cast<ValueType*>bar : 0;
}

How is the return statement evaluated? Like so?

if ((bar && typeid(bar)) == typeid(ValueType))
    return &static_cast<ValueType*>bar
return false;

Upvotes: 1

Views: 122

Answers (2)

Lundin
Lundin

Reputation: 213306

The posted answer correctly addresses operator precedence with this:

(foo && (typeid(foo) == typeid(ValueType))) ? (&(static_cast<ValueType*>(bar))) : 0;

That's how the expression will be parsed - which operands the compiler will regard as if belonging to which operator. That does however not state how the expression is evaluated (basically "executed"). So it does not answer the question:

How is this boolean expression evaluated?

The expression is evaluated as:

  • foo is evaluated.
    • If false, then (typeid(foo) == typeid(ValueType)) will not get evaluated and the whole subexpression will be evaluated as false.
    • If true then (typeid(foo) == typeid(ValueType)) will get evaluated. Both operands of the == will get evaluated (and overloaded operators called if applicable). If that whole expression is true then the result of the && is also true.
  • If the result of the previous evalution was true, then the 2nd operand (&(static_cast<ValueType*>(bar))) will get evaluated.
  • Otherwise if the result of the previous evaluation was false, then the 3rd operand 0 will get evaluated.

Notably, the 2nd and 3rd operands of ?: need to be of the same type. In case of pointers that means exactly the same type, although if one operand is a null pointer as in this case, the result will be of the type of the other operand. In case of arithmetic types, the 2nd and 3rd operand will get "balanced" as per the usual arithmetic conversions.

The expression &static_cast<ValueType*>bar is also very fishy in many ways. Apart from the missing parenthesis, you cannot cast bar to a pointer type and you mostly likely shouldn't be doing wild type punning between types like this either.

Upvotes: 0

Tony Delroy
Tony Delroy

Reputation: 106068

foo && typeid(foo) == typeid(ValueType) ? &static_cast<ValueType*>bar : 0;

...corrected with parenthesis after the static_cast<>, is evaluated as...

(foo && (typeid(foo) == typeid(ValueType))) ? (&(static_cast<ValueType*>(bar))) : 0;

The precedence rules are listed here. Notice that the ?: ternary operator is at precedence level 15 in this list - lower than the other operators you've used, so it defines the outer structure of the evaluation. && is at 13 - way below == at 9. (I don't think these numbers are used anywhere in the Standard, but they're convenient references for pointing out things in the cppreference table).

Upvotes: 5

Related Questions