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


115

我在进行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进行了倒钩,因为条件运算符中的类型不同。因此,throw表达式的类型似乎不是无效的。

那是什么

如果您回答,请用标准引号备份您的陈述。


事实证明,与条件表达式如何处理throw表达式无关,它与throw表达式的类型无关。我在今天之前当然还不了解这一点。感谢所有答复,特别是大卫·桑利。

c++  throw 

10
+1很棒的问题。以及一种聪明的测试方法。
杰里米·鲍威尔,2009年

1
该链接似乎很清楚地表明,该类型由编译器确定为所需的类型。
Draemon

自从我看过链接文章以来,我认为它已被更新,并且我相信事实确实如此。但是,我在标准中找不到它。

也许不是-双d =抛出“ foo”; 与G + =错误(没有与科莫测试它)

+1我很好奇知道答案。
AraK

Answers:


96

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

实际上,在15.1第1段中明确指出“ throw-expression类型为void。”


9
好-我想我们有赢家。

注意throw-expression是赋值表达式。因此,对于大多数运算符来说,它们是语法错误。显然,您可以将它们隐藏在括号中,但是如果不忽略它们(例如,内置运算符的第一个参数),则是类型错误。
AProgrammer

4
真正令我惊讶的是,他们想到了这个案子,并做了一些合理的事情。
2010年

31

“ throw-expression类型为void”

ISO14882第15节


那么g ++和Comeau都没有为我的// 1情况给出错误而被遗忘了吗?

2
@Neil,不是真的,因为根据C ++ / 5.16 / 2,条件运算符的第二和第三操作数的类型可以是void
mloskot 2010年

13

从[expr.cond.2](条件运算符?:)中:

如果第二个或第三个操作数具有类型(可能是cv限定)的void,则对第二个和第三个操作数执行左值到右值,数组到指针和函数到指针的标准转换,并且符合下列条件之一:

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

—第二和第三操作数的类型均为void;结果是void类型,是一个右值。[注意:这包括两个操作数均为throw-expressions的情况。—尾注]

因此,//1在第一种情况下,如果使用with //2,则您违反了“以下任一条件成立”,因为在这种情况下,它们都不起作用。


3

您可以让类型打印机为您吐出它

template<typename T>
struct PrintType;

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

基本上缺少实现PrintType会导致编译错误报告说:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.