tags:

views:

1734

answers:

3

I picked this up in one of my brief forays to reddit:

http://www.smallshire.org.uk/sufficientlysmall/2009/07/31/in-c-throw-is-an-expression/

Basically, the author points out that in C++:

throw "error"

is an expression. This is actually fairly clearly spelt out in the C++ Standard, both in the main text and the grammar. However, what is not clear (to me at least) is what is the type of the expression? I guessed "void", but a bit of experimenting with g++ 4.4.0 and Comeau yielded this code:

    void f() {
    }

    struct S {};

    int main() {
        int x = 1;
        const char * p1 = x == 1 ? "foo" : throw S();  // 1
        const char * p2 = x == 1 ? "foo" : f();        // 2
    }

The compilers had no problem with //1 but barfed on //2 because the the types in the conditional operator are different. So the type of a throw expression does not seem to be void.

So what is it?

If you answer, please back up your statements with quotes from the Standard.


This turned out not to be so much about the type of a throw expression as how the conditional operator deals with throw expressions - something I certainly didn't know about before today. Thanks to all who replied, but particularly to David Thornley.

+20  A: 

"A throw-expression is of type void"

ISO14882 Section 15

Draemon
Then both g++ and Comeau are remiss in not giving an error for my //1 case?
anon
@Neil, not really because according to C++/5.16/2, second and third operands of the conditional operator can be of type of `void`
mloskot
+61  A: 

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

David Thornley
OK - I think we have a winner.
anon
Note that throw-expression are assignment-expression. So they are a syntax error as an argument to most operators. Obviously, you can hide them in parenthesis, but if they aren't ignored (first argument of builtin operator , for instance), it is a type error.
AProgrammer
What really surprises me is that they thought of this case and made something reasonable happen.
Omnifarious
+7  A: 

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.