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

别说谁变了你拦得住时间么 提交于 2019-11-27 05:06:38

问题


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.


回答1:


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




回答2:


"A throw-expression is of type void"

ISO14882 Section 15




回答3:


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.




回答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)



来源:https://stackoverflow.com/questions/1212978/in-c-if-throw-is-an-expression-what-is-its-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!