2017-11-24 4 views
4

これは私はそれがemplaceバリアントは無価値この例では、std :: variantはvalueless_by_exceptionになりますか?

になった原因という意味

真、偽

を出力しようとした1つのコンパイラのcppreference

struct S { 
    operator int() { throw 42; } 
}; 


int main(){ 
    variant<float, int> v{12.f}; // OK 
    cout << std::boolalpha << v.valueless_by_exception() << "\n"; 
    try{ 
     v.emplace<1>(S()); // v may be valueless 
    } 
    catch(...){ 
    } 
    cout << std::boolalpha << v.valueless_by_exception() << "\n"; 
} 

からの例に触発された例です。

私が理解していないことは、これがどのように起こったかです。 特に私はemplaceが全く呼び出されない理由を理解していませんが、Sからint引数のスローへの変換以来、プログラムはそれを呼び出さないと思います。

+2

'main'ではなく' emplace'関数の内部で変換が行われます。 – Jarod42

答えて

5

注関連std::variant::emplace過負荷のための署名:それはフォワーディング参照のパックを取る

template <size_t I, class... Args> 
std::variant_alternative_t<I, variant>& emplace(Args&&... args); 

。これは、関数の引数を評価するときに変換演算子がSからintまで呼び出されないことを意味します。それはemplaceの体の中で呼ばれています。 intをその場で構築しようとすると失敗するため、バリアントは例外によって無価値になります。

実現可能な型の場合、古い値が保存されてから、失敗した場合に元の値が保存されるように実装することは可能でしょうが、標準によって与えられた型の実装に対する様々な制限。

+1

ここでの設計上の意思決定については、このhttps://cbeck88.github.io/strict-variant/strict_variant/overview/design.html – NoSenseEtAl

+0

の素晴らしいリンクです。「タイプのさまざまな制限に適合するかどうかわかりません実装は標準によって与えられています。私はこの説明がリブ・リフレクターに引用されているのを聞いたことがあります。なぜなら、 "emplace"という言い回しが、初期化がスローされれば "*値を保持しないかもしれない"と言っているが、現在は含まれている値を破壊する'valueless_by_exception()'が 'false'の場合。" as "は、現在含まれている値のコピーを作成し、あとで' variant'に再挿入します。 – Casey

+2

Boostは決して空の保証をしていません...この場合、 'boost :: variant'は' float'の古い値を保存すると思います。まれに、noexceptとして値を復元する方法がない場合は、ヒープ割り当てと "ダブルバッファリング"を使用します。 'valueless_by_exception'はパフォーマンス上の理由から、そして' boost :: variant'の失敗モードが非常に驚くかもしれないので、空ではない保証の代わりに 'std :: variant'に選ばれました。 –

関連する問題