一時的にパイプされた範囲操作に戻すことはできますか?


9

generate_my_rangea range(特にis regular)をモデル化するクラスがあるとします。次のコードは正しいですか:

auto generate_my_range(int some_param) {    
  auto my_transform_op = [](const auto& x){ return do_sth(x); };
  return my_custom_rng_gen(some_param) | ranges::views::transform(my_transform_op);
}
auto cells = generate_my_range(10) | ranges::to<std::vector>;

my_custom_rng_gen(some_param)(最初の)パイプ演算子によって値が取得されますか、またはgenerate_my_rangeスコープを離れると、ダングリング参照がありますか?

関数呼び出しと同じranges::views::transform(my_custom_rng_gen(some_param),my_transform_op)でしょうか?

左辺値参照を使用した場合、それは正しいでしょうか?例えば:

auto generate_my_range(int some_param) {
  auto my_transform_op = [](const auto& x){ return do_sth(x); };
  auto tmp_ref = my_custom_rng_gen(some_param);
  return tmp_ref | ranges::views::transform(my_transform_op);
}

範囲がこれらの操作の値によって取得される場合、コンテナーに左辺値参照を渡すとどうなりますか?ranges::views::all(my_container)パターンを使用する必要がありますか?


my_custom_rng_gen(some_param)はすでに制限されていますか?take(5)がないgodbolt.org/z/aTF8RNのようなものですか?
Porsche9II

@ Porsche9IIはい、これは境界範囲です。コンテナだとしましょう
ベレンジャー

回答:


4

範囲ライブラリには、2種類の操作があります。

  • レイジーで、基礎となるコンテナーが存在する必要があるビュー
  • 熱心で、結果として新しいコンテナーを生成する(または既存のコンテナーを変更する)アクション

ビューは軽量です。それらを値で渡し、基礎となるコンテナーが有効で変更されないままであることを要求します。

範囲-v3のドキュメント

ビューは、要素の基本的なシーケンスのビューを、それを変更したりコピーしたりせずにカスタムの方法で表示する軽量ラッパーです。ビューは安価に作成およびコピーでき、所有していない参照セマンティクスがあります。

そして:

イテレータまたはセンチネルを無効にする基になる範囲に対する操作は、その範囲の任意の部分を参照するビューも無効にします。

基礎となるコンテナーの破壊は明らかにそれに対するすべてのイテレーターを無効にします。

あなたのコードでは、具体的にはビューを使用しています -あなたが使用していますranges::views::transform。パイプは、それがそうであるように書くことを簡単にするための単なる構文上の砂糖です。パイプの最後のものを見て、何が生成されるかを確認する必要があります。この場合、それはビューです。

パイプ演算子がない場合、おそらく次のようになります。

ranges::views::transform(my_custom_rng_gen(some_param), my_transform_op)

そのように接続された複数の変換があった場合、どれほど醜いかがわかります。

したがって、my_custom_rng_gen何らかのコンテナを生成し、それを変換してから返す場合、そのコンテナは破棄され、ビューから参照がぶら下がっています。my_custom_rng_genこれらのスコープの外にあるコンテナの別のビューである場合、すべてが問題ありません。

ただし、コンパイラーは、一時コンテナーにビューを適用していることを認識し、コンパイルエラーでヒットする必要があります。

関数で範囲をコンテナとして返す場合は、結果を明示的に「具体化」する必要があります。そのためには、ranges::to関数内で演算子を使用します。


更新:あなたのコメントをより明確にするために、「ドキュメントでは、範囲/配管を構成するとビューが取得され、保存されると記載されていますか?」

パイプは、読みやすい式で物事を接続するための単なる構文上の砂糖です。使用方法に応じて、ビューが返される場合と返されない場合があります。それは右側の引数に依存します。あなたの場合は:

`<some range> | ranges::views::transform(...)`

したがって、式は何でもviews::transform返します。

今、変換のドキュメントを読むことによって:

以下は、Range-v3が提供する遅延範囲コンビネーター、またはビューのリストと、それぞれの使用方法についての概要です。

[...]

views::transform

ソース範囲と単項関数を指定すると、各結果要素が単項関数をソース要素に適用した結果である新しい範囲を返します。

したがって、範囲を返しますが、遅延演算子なので、返される範囲すべてのセマンティクスを持つビューです。


OK。私にとって少し不思議なのは、コンテナーをパイプ(つまり、コンポジションによって作成された範囲オブジェクト)に渡したときの動作です。どういうわけかコンテナのビューを保存する必要があります。それで終わりranges::views::all(my_container)ですか?そして、ビューがパイプに渡された場合はどうなりますか?コンテナまたはビューが渡されたことを認識しますか?する必要がありますか?どうやって?
ベレンジャー

「コンパイラーは、一時コンテナーにビューを適用していることを認識し、コンパイルエラーでヒットする必要があります。」これも私が考えたところです。値)が満たされていません。そのようなことはrange-v3によって行われます。ただし、この場合は問題ありません。コンパイルして実行します。したがって、未定義の動作がある可能性がありますが、表示されません。
ベレンジャー

コードが誤って正しく実行されたかどうか、またはすべてが正常かどうかを確認するには、の内容を確認する必要がありmy_custom_rng_genます。パイプとtransformフードの下での相互作用の正確さは重要ではありません。式全体が引数として範囲(コンテナーまたはあるコンテナーのビュー)を取り、そのコンテナーに別のビューを返します。戻り値はビューであるため、コンテナーを所有することはありません。
CygnusX1

1

ranges-v3のドキュメントから抜粋

ビューには、所有していない参照セマンティクスがあります。

そして

単一の範囲オブジェクトを持つことで、操作のパイプラインが許可されます。パイプラインでは、範囲はなんらかの方法で遅延適応または熱心に変異され、その結果はすぐにさらなる適応または変異に利用できます。遅延適応はビューによって処理され、熱心な変更はアクションによって処理されます。

// taken directly from the the ranges documentation
std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace ranges;
auto rng = vi | views::remove_if([](int i){ return i % 2 == 1; })
              | views::transform([](int i){ return std::to_string(i); });
// rng == {"2","4","6","8","10"};

上記のコードでは、rngは、基になるデータへの参照と、フィルターおよび変換関数を格納するだけです。rngが反復されるまで、作業は行われません。

一時的な範囲はコンテナと考えることができると述べたので、関数はぶら下がり参照を返します。

言い換えると、基礎となる範囲がビューよりも長く存続することを確認する必要があります。そうしないと、問題が発生します。


はい、ビューは非所有ですが、ドキュメンテーションはどこに範囲/配管の構成がビューを取得して保存すると言っていますか?範囲が右辺値参照で指定されている場合は、値で格納するというポリシーを使用することは可能です(私は良いことだと思います)。
ベレンジャー

1
@Bérengerレンジのドキュメントからもう少し追加しました。しかし重要なのは、ビューは非所有であるということです。右辺値を渡すかどうかは関係ありません。
Rumburak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.