【问题标题】:In C++, if throw is an expression, what is its type?在 C++ 中,如果 throw 是一个表达式,它的类型是什么?
【发布时间】:2010-11-15 19:49:56
【问题描述】:

我在一次短暂的 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。

【问题讨论】:

  • +1 很棒的问题。以及一种巧妙的测试方式。
  • 该链接似乎相当清楚地表明,类型由编译器确定为所需的任何类型。
  • 我认为链接的文章在我查看后已经更新,我确信事实确实如此。但是,我在标准中找不到它。
  • 也许不是 - double d = throw "foo";是 g+= 的错误(没有用 comeau 测试过)
  • +1 我很想知道答案。

标签: c++ throw


【解决方案1】:

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

ISO14882 第 15 节

【讨论】:

  • 那么 g++ 和 Comeau 都没有为我的 //1 案例提供错误?
  • @Neil,不是真的因为根据 C++/5.16/2,条件运算符的第二个和第三个操作数可以是 void 的类型
【解决方案2】:

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

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

【讨论】:

  • 好的 - 我想我们赢了。
  • 请注意 throw-expression 是 assignment-expression。因此,作为大多数运算符的参数,它们是语法错误。显然,您可以将它们隐藏在括号中,但如果它们没有被忽略(例如,内置运算符的第一个参数),那就是类型错误。
  • 真正让我吃惊的是,他们想到了这个案子并做出了一些合理的事情。
【解决方案3】:

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

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

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

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

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

【讨论】:

    【解决方案4】:

    你可以有打字机spit it out for you

    template<typename T>
    struct PrintType;
    
    int main()
    {
        PrintType<decltype(throw "error")> a; 
    }
    

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

    未定义模板PrintType&lt;void&gt;的隐式实例化

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

    【讨论】:

      猜你喜欢
      • 2017-12-09
      • 2018-08-06
      • 1970-01-01
      • 2019-10-30
      • 2013-09-18
      • 2017-10-06
      • 2015-07-22
      • 1970-01-01
      • 2015-06-19
      相关资源
      最近更新 更多