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

这是我在 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表达式的类型似乎不是无效的。

那是什么?

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


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 感谢所有回复的人,特别是大卫 · 索恩利

5865 次浏览

“ throw 表达式为 void 类型”

ISO14882第15条

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

事实上,15.1第1段明确说明“ throw-expression 的类型为 void。”

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

如果第二个或第三个操作数具有 void 类型(可能是 cv 限定的) ,则 lvalue-to-rvalue, 数组到指针的标准转换和函数到指针的标准转换在第二个和 第三个操作数和下列其中一个操作数应包含:

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

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

因此,对于 //1,你在第一种情况下,对于 //2,你违反了“下列之一将持有”,因为在这种情况下,它们都不会持有。

You can have a type printer 说吧 :

template<typename T>
struct PrintType;


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

基本上,PrintType缺乏实现将导致编译错误报告说:

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

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