Throw and ternary operator in C++
It is standard C++. Either (or both) of the then/else expressions in a conditional expression is allowed to be a throw-expression instead (C++98 5.16/2).
If Visual Studio crashes when compiling it... that would seem to be unfortunate!
Throwing with the ternary operator
A
and B
are different, incompatible types, so the expression true ? A() : B()
is ill-typed (it'd have to be either an A
or a B
).
Move or throw using the ternary operator
This has to be a bug.
Either the move will be a move or the compilation should fail due to attempted copy of a unique_ptr
(or a throw
occurs in which case it doesn't matter).
q.get() == p.get()
indeed shows that the internals have broken down, as this should not be possible.
I'd agree with cpplearner that this is bug 90393 (and all its dupes), which is reported as having been introduced in GCC 9.1.
Either downgrade, wait to upgrade, or reform your code into a nice if
/else
. /p>
Can an exception be thrown from the ternary operator?
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!
Ternary operator: exception throwing and nesting
? :
has lower precedence than &&
, so yes, your first two examples are equivalent.
As for your third example, I'd write that as
int getIndex(int i) throw(Exception) {
return
i < 0 || i >= capacity ? throw IndexOutOfBoundsException() :
i >= length ? throw IndexOfEmptyFieldException() :
array[i]
;
}
I think "nested" conditional operators are fine as long as they're "serialized", i.e. they form what amounts to an if/elsif/else chain.
This particular case is debatable though, because only one branch actually returns a value. The other two just throw an exception, and that's usually nicer as a separate statement: Throwing an exception has no real value as an expression; it's used solely for its side effects.
Return throwing ternary operator?
Your example is valid and well-defined (assuming suitable definitions of Size
and _data
). As to "oftenly used" - I personally have never seen such a construct before, for what it's worth.
C++: Always-Throw function in conditional expression
You can use the comma operator like so:
int a = true ? 1 : (throw std::exception(), 0);
int b = true ? 1 : (foo(), 0);
See it working on godbolt.org.
Related Topics
How Can Duff's Device Code Be Compiled
Do You Know Tool Building Tree of Include Files in Project\File
Why Can't I Use Inheritance to Implement an Interface in C++
How to Use Gpu::Stream in Opencv
Unary Plus (+) Against Literal String
How to Typedef a Type and the Same Type's Pointer
Fibonacci Sequence Overflow, C++
How to Test Whether Class B Is Derived from Template Family of Classes
How to Get Hwnd of Window Opened by Shellexecuteex.. Hprocess
Reading and Writing a Std::Vector into a File Correctly with Iterators
Can the Hwnd from Createwindow/Createdialog Be Getmessage'D from Another Thread