According to the standard, 5.16 paragraph 2 first point, "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 an rvalue." Therefore, the conditional operator doesn't care what type a throw-expression is, but will just use the other type.
In fact, 15.1, paragraph 1 says explicitly "A throw-expression is of type void."
"A throw-expression is of type void"
ISO14882 Section 15
From [expr.cond.2] (conditional operator ?:
):
If either the second or the third operand has type (possibly cv-qualified) void, then the lvalue-to-rvalue, array-to-pointer, and function-to-pointer 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; the result is of the type of the other and is an rvalue.
— Both the second and the third operands have type void; the result is of type void and is an rvalue. [ Note: this includes the case where both operands are throw-expressions. — end note ]
So, with //1
you were in the first case, with //2
, you were violating "one of the following shall hold", since none of them do, in that case.
You can have a type printer spit it out for you :
template<typename T>
struct PrintType;
int main()
{
PrintType<decltype(throw "error")> a;
}
Basically the lack of implementation for PrintType
will cause the compilation error report to say :
implicit instantiation of undefined template
PrintType<void>
so we can actually verify that throw
expressions are of type void
(and yes, the Standard quotes mentioned in other answers verify that this isn't an implementation specific outcome - though gcc has a hard time printing valuable info)
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