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


115

私は簡単な進路の1つでこれを拾い、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とコモーで少し実験すると、次のコードが生成されました。

    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に感謝します。

c++  throw 

10
+1すばらしい質問。そしてそれをテストする賢い方法。
ジェレミーパウエル

1
そのリンクは、型が必要なものであるようにコンパイラーによって決定されることをかなり明確にするようです。
ドラえもん2009

リンクされた記事は、それを見て以来更新されたと思いますが、確かにそうです。しかし、私はそれを標準で見つけることができません。

Aおよび多分そうではありません-double d = "foo"をスローします。g + =のエラーです(comeauでテストしていません)

+1答えを知りたいです。
AraK、2009

回答:


96

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

実際、15.1のパラグラフ1は、「throw式はvoid型です」と明示的に述べています。


9
OK-勝者はいると思う。

throw-expressionは割り当て式であることに注意してください。したがって、これらはほとんどの演算子の引数としての構文エラーです。明らかに、括弧でそれらを隠すことができますが、それらが無視されない場合(例えば、組み込み演算子の最初の引数)、それは型エラーです。
AProgrammer 2009

4
私が本当に驚いたのは、彼らがこの事件を考え、合理的なことを起こしたことです。
10

31

「スロー式はvoid型です」

ISO14882セクション15


次に、g ++とコモーの両方が私の// 1ケースにエラーを出さないことを怠っていますか?

2
@Neil、実際にはそうではありません。C++ / 5.16 / 2によると、条件演算子の2番目と3番目のオペランドの型はvoid
mloskot

13

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

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

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

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

したがって、//1あなたが最初のケースにいた場合、は//2、「次のいずれかが保持される」に違反していました。


3

タイププリンターに出力させることができます

template<typename T>
struct PrintType;

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

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

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

したがって、throw式がタイプであることを実際に確認できvoidます(そして、はい、他の回答で言及されている標準的な引用は、これが実装固有の結果ではないことを確認します-gccは貴重な情報を出力するのに苦労します)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.