In C++, if throw is an expression, what is its type?
Asked Answered
P

4

118

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.

Piping answered 31/7, 2009 at 14:50 Comment(3)
That link seems to make it fairly clear that the type is determined by the compiler to be whatever it needs to be.Edifice
The linked article has I think been updated since I looked at it, and I'm sure that is in fact the case. However, I can't find it in the standard.Piping
Aand maybe not - double d = throw "foo"; is an error with g+= (haven't tested it with comeau)Piping
T
97

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

Tallman answered 31/7, 2009 at 15:4 Comment(3)
OK - I think we have a winner.Piping
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.Eyecatching
What really surprises me is that they thought of this case and made something reasonable happen.Miles
E
33

"A throw-expression is of type void"

ISO14882 Section 15

Edifice answered 31/7, 2009 at 15:3 Comment(2)
Then both g++ and Comeau are remiss in not giving an error for my //1 case?Piping
@Neil, not really because according to C++/5.16/2, second and third operands of the conditional operator can be of type of voidEmergent
H
13

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.

Harvester answered 31/7, 2009 at 15:7 Comment(0)
I
4

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)

Impudence answered 3/7, 2015 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.