在 C++ 中,如果 throw 是一个表达式,那么它的类型是什么?

发布于 2024-07-30 00:39:45 字数 946 浏览 11 评论 0 原文

我在一次短暂访问 reddit 时发现了这一点:

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

基本上,作者指出在 C++ 中:

throw "error"

是一个表达式。 实际上,C++ 标准在正文和语法中都相当清楚地阐明了这一点。 然而,不清楚(至少对我来说)的是表达式的类型是什么? 我猜是“void”,但是对 g++ 4.4.0 和 Comeau 进行了一些实验,得到了以下代码:

    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
    }

编译器对 //1 没有问题,但对 //2 却感到厌烦,因为 //2 中的类型条件运算符不同。 所以 throw 表达式的类型似乎不是 void。

那么它是什么?

如果您回答,请引用该标准来支持您的陈述。


事实证明,这与抛出表达式的类型无关,而与条件运算符如何处理抛出表达式有关 - 我当然不知道 今天之前就知道了。 感谢所有回复的人,特别是大卫·索恩利。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

牵你的手,一向走下去 2024-08-06 00:39:45

根据标准,5.16第2段第一点,“第二个或第三个操作数(但不是两者)是一个抛出表达式(15.1);结果是另一个的类型,并且是一个右值。” 因此,条件运算符并不关心 throw 表达式是什么类型,而只会使用其他类型。

事实上,15.1 第 1 段明确指出“抛出表达式的类型为 void”。

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

迷荒 2024-08-06 00:39:45

“抛出表达式的类型为 void”

ISO14882 第 15 节

"A throw-expression is of type void"

ISO14882 Section 15

缘字诀 2024-08-06 00:39:45

来自 [expr.cond.2](条件运算符 ?:):

如果第二个或第三个操作数的类型(可能是 cv 限定的)void,则左值到右值,
数组到指针和函数到指针的标准转换在第二个和
第三个操作数,并且以下之一应成立:

——第二个或第三个操作数(但不是两者)是一个 throw 表达式;
结果是另一个的类型,并且是一个右值。

——第二个和第三个操作数的类型都是void;
结果是 void 类型并且是右值。
[ 注意:这包括两个操作数都是 throw 表达式的情况。 ——尾注]

因此,使用 //1 你处于第一种情况,使用 //2 ,你违反了“以下其中一个应成立”,因为没有在这种情况下,他们中的一些人会这样做。

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.

携余温的黄昏 2024-08-06 00:39:45

您可以使用打字打印机 为您吐出内容

template<typename T>
struct PrintType;

int main()
{
    PrintType<decltype(throw "error")> a; 
}

基本上缺乏 < code>PrintType 将导致编译错误报告显示:

未定义模板的隐式实例化PrintType

因此我们实际上可以验证 throw 表达式的类型为 void (是的,提到的标准引号在其他答案中验证这不是特定于实现的结果 - 尽管 gcc 很难打印有价值的信息)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文