web-dev-qa-db-ja.com

C ++では、throwが式の場合、その型は何ですか?

私はこれをredditへの短い試みの1つで拾いました:

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式のタイプは無効ではないようです。

それで、それは何ですか?

回答する場合は、標準からの引用でステートメントをバックアップしてください。


これは、条件演算子がスロー式を処理する方法ほど、スロー式のタイプについてではないことが判明しました-今日まで私が確かに知らなかったことです。返信してくれたすべての人に感謝しますが、特にDavid Thornleyに感謝します。

115
anon

標準の5.16段落2の最初のポイントによると、「2番目または3番目のオペランド(両方ではない)はスロー式(15.1)であり、結果はもう一方の型であり、右辺値です。」したがって、条件演算子は、throw-expressionがどのタイプであるかを気にせず、他のタイプを使用するだけです。

実際、15.1、段落1は、「throw-expressionはvoid型です」と明示的に述べています。

96
David Thornley

「throw-expressionはvoid型です」

ISO14882セクション15

31
Draemon

[expr.cond.2]から(条件演算子?:):

2番目または3番目のオペランドのいずれかがタイプ(おそらくcv修飾)voidである場合、左辺値から右辺値、配列からポインター、および関数からポインターの標準変換が2番目と3番目のオペランドで実行されます。次のいずれかが成立します。

— 2番目または3番目のオペランド(両方ではない)はスロー式です。結果は他のタイプであり、右辺値です。

—2番目と3番目のオペランドはどちらもvoid型です。結果はvoid型であり、右辺値です。 [注:これには、両方のオペランドがスロー式である場合が含まれます。 —エンドノート]

したがって、//1あなたは最初のケースで、//2、あなたは「次のいずれかが成立する」に違反していました。その場合、いずれも違反していません。

13

あなたはタイププリンターを持つことができます あなたのためにそれを吐き出してください

template<typename T>
struct PrintType;

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

基本的に、PrintTypeの実装がないため、コンパイルエラーレポートに次のように表示されます。

未定義のテンプレートの暗黙的なインスタンス化PrintType<void>

したがって、throw式がvoid型であることを実際に確認できます(もちろん、他の回答で言及されている標準引用符は、これが実装固有の結果ではないことを確認しています-gccは苦労していますが貴重な情報を印刷する)

3