Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an exception be thrown from the ternary operator?

Tags:

Sometimes it is convenient or even necessary to have a function which just one statement (it is necessary when returning a constexpr). If a condition needs to be checked and only one statement is allowed, the conditional operator is the only option. In case of an error it would be nice to throw an exception from the conditional operator, e.g.:

template <typename It> typename std::iterator_traits<It>::reference access(It it, It end) {     return it == end? throw std::runtime_error("no element"): *it; } 

The above function doesn't compile, however, when used for example as (live example):

std::vector<int> v; access(v.begin(), v.end()); 

The compiler complains about trying to bind a non-const reference to a temporary. The compiler doesn't complain about the throw-expression per se, though. So the question: Can exceptions be thrown from the conditional operator and, if so, what's going wrong with the above code?

like image 890
Dietmar Kühl Avatar asked Dec 30 '13 21:12

Dietmar Kühl


People also ask

How do you handle 3 conditions in a ternary operator?

The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.

Why we should not use ternary operator?

They simply are. They very easily allow for very sloppy and difficult to maintain code. Very sloppy and difficult to maintain code is bad. Therefore a lot of people improperly assume (since it's all they've ever seen come from them) that ternary operators are bad.

Is nesting possible using ternary operator?

Nested Ternary operator: Ternary operator can be nested.

Can ternary operator return string?

Ternary operator values The values part of the ternary operator in the above example is this: “This is an even number!” : “This is an odd number!”; In the example above, if the condition evaluates to true then the ternary operator will return the string value “This is an even number!”.


2 Answers

The conditional operator is described in 5.16 [expr.cond]. Its paragraph 2 includes the following text:

The second or the third operand (but not both) is a throw-expression (15.1); the result is of the type of the other and is a prvalue.

That says that it is allowed to throw an exception from the conditional operator. However, even if the other branch is an lvalue, it is turned into an rvalue! Thus, it isn't possible to bind an lvalue to the result of a conditional expression. Aside from rewriting the condition using the comma operator, the code could be rewritten to only obtain the lvalue from the result of the conditional operator:

template <typename It> typename std::iterator_traits<It>::reference access(It it, It end) {     return *(it == end? throw std::runtime_error("no element"): it); } 

The somewhat tricky business is that returning a const reference from the function would compile but actually return a reference to a temporary!

like image 91
Dietmar Kühl Avatar answered Nov 09 '22 23:11

Dietmar Kühl


The wording in the standard is around 5.16/2:

If either the second or the third operand has type void, then the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the second and third operands, and one of the following shall hold:

— The second or the third operand (but not both) is a throw-expression (15.1); the result is of the type of the other and is a prvalue.

Which explains the behavior you are getting. It is legal to throw, but the type of the expression is a pure-rvalue (even if the expression is an lvalue) and you cannot thus bind a non-const lvalue-reference

like image 40
David Rodríguez - dribeas Avatar answered Nov 10 '22 01:11

David Rodríguez - dribeas