116

我在对 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 表达式——这在今天之前我当然不知道。感谢所有回复的人,尤其是 David Thornley。

4

4 回答 4

96

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

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

于 2009-07-31T15:04:09.187 回答
32

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

ISO14882 第 15 节

于 2009-07-31T15:03:19.903 回答
13

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

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

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

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

因此,//1在第一种情况下,//2您违反了“以下一项应成立”,因为在这种情况下,他们都没有这样做。

于 2009-07-31T15:07:52.160 回答
3

你可以让打字机帮你打印出来

template<typename T>
struct PrintType;

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

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

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

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

于 2015-07-03T10:42:27.213 回答