2016-08-04 14 views
20

"noexcept指定子(と演算子)"について学ぶと、私は簡単なコードを書いた。 noexcept指定されC++ 17例外指定型システムはどのように機能しますか?

void asdf() noexcept {} 
int main() 
{ 
    auto f = asdf; 
    std::cout << std::boolalpha << noexcept(f()) << std::endl; 
} 

プリントfalse、でも機能「空自」:そして、私は、コードのこの部分ということに驚いています。

なぜこの神秘的な現象が起きているのかを調べるうちに、C++ 17の「例外指定型システム」 - P0012R1が見つかりました。

この(提案された)提案によれば、C++ 17以降、 noexceptは関数型の一部ですので、上記のコードは印刷されますtrue

そしてもう一つ、this質問の1行で:

std::function<void() noexcept> f 

noexcept指定は、C++ 14または11 C++ 17で意図したとおり、このコード作業は意志を無視でいるようですか?

+0

g ++ 'nostcept(f())'の '-std = C++ 1z'(ただし、clangは' false'を返します)では 'true'を返します。 – Holt

+0

余分な楽しみのために、 'auto f = asdf;'を 'void(* f)()noexcept = asdf;'に変更してください。現在、GCCは 'false'を出力し、clangは' true'を出力します。 – hvd

+0

@Holt情報ありがとうございます。私はMSVCを使用しています( 'false'を返します)。何が違うのでしょうか?これはg ++やC++のバグですか?14以前の標準では、 'noexcept'型のシステムについて何も指定されていませんか? – Gear

答えて

11

この(提案された)提案によると、C++ 17以降では、 noexceptは関数型の一部なので、上のコードはtrue

はい。 asdfに適用される関数へのポインタ変換はnoexceptプロパティを保存するためf

タイプvoid(*)() noexceptに推測されるであろう。 noexcept関数ポインタへの呼び出しは、その部分式の1つがそうでない限り、例外をスローすることはできません。

正確な表現については、[expr.unary.noexcept]/3および[expect.spec]/13を参照してください。後者の段落のC++ 17ドラフトからの新しい表現は、OPでリンクされているP0012R1に由来することに注意してください。

noexcept演算子の結果は、式([except.spec])の潜在的な例外のセットが空の場合trueであり、そうでなければfalse。その後置表現は(おそらく括弧)ID-式である場合

  • ...

    • e場合は、関数呼び出し([expr.call])でありますキャスト式のid式であるクラスメンバアクセス([expr.prim.id])、クラスメンバアクセス([expr.ref])、またはメンバへのポインタ操作([expr.mptr.oper]) 、Sは、含まれるid式によって選択されたエンティティの例外仕様のタイプのセットです(該当する場合は、過負荷解決後)。 ...

だからf()の潜在的な例外のセットは、fnoexcept宣言されているので、空であるfの例外仕様に型のセットと同じです。

はのは、2番目の質問に移りましょう:

noexcept指定は、C++ 14または11 C++ 17で意図したとおり、このコード作業は意志を無視でいるようですか?

あなたの質問はそうであるように思われます:std::function<void() noexcept>例外をスローする機能を保持することを拒否しますか?

私はそれがとはっきりしないと言います。標準の現在の文言では、は実際には定義されておらず、ちょうどstd::function<double(float) const> is not definedと定義されています。 noexceptは関数の型の一部とはみなされなかったので、これはもちろんC++ 14では問題ではありませんでした。

std::function<void() noexcept>はC++で単純にブレークしますか17?それは私には不確実です。どのような振る舞いが「すべきか」を推測するために現在の言葉を見てみましょう。

標準は、引数の型ArgTypes...と戻り型Rは、「左辺値、呼び出し可能」であるとstd::function<R(ArgTypes..)>のコンストラクタへの引数を必要とするmeans

呼び出し可能なタイプ([func.def])F評価されないオペランド(句[expr])と見なされる式INVOKE(declval<F&>(), declval<ArgTypes>()..., R)が整形式([func.require])の場合は、Lvalue-Callableの引数タイプはArgTypesで戻り値タイプはRです。

おそらく、関数型がnoexceptであれば、その後、noexcept(INVOKE(...))は同様に真でなければならないという追加の要件があるはずです。それにもかかわらず、この言葉は現在の草案にはない。 P0012R1で

、というコメントがあります:それはstd::functionを通じて "noexcept" を伝播する方法未解決の問題である

が。

この追加要件が課された場合、std::functionがどのように実装されるかはわかりません。うまくいけば、他の誰かが詳細を提供することができます。

+1

明らかに 'std :: function_moveonly'と' std :: function_noexceptonly'と 'std :: function_moveonly_noexceptonly'が必要です。しかし、 'std :: function_mutablecall'はどうでしょうか?これは乱雑になる可能性があります。 – Yakk

関連する問題