[C++] <ranges>のviewを見る19 - owning_view
owning_view
owning_view
は右辺値の範囲を所有して、安全に取り扱えるようにするためのview
です。
#include <ranges>
auto f() -> std::vector<int> {
return {1, 2, 3, 4, 5};
}
int main() {
std::ranges::owning_view ov{f()};
// 安全に使用可能
for (int n : ov) {
std::cout << n; // 12345
}
}
owning_view
は右辺値のrange
を受け取って、それをムーブして内部に保持することで右辺値範囲の寿命を延長させます。それ以外の部分は受けたrange
のごく薄いラッパーなので、元のrange
の性質をそのまま受け継ぎつつview
となります。
owning_view<R>
はrange
であるR
の右辺値だけを受け取る事ができて、左辺値から構築する事はできません。また、R
はmovable
である必要があります。
views::all
owning_view
に対応するrange adaptor objectがstd::views::all
です。
#include <ranges>
auto f() -> std::vector<int> {
return {1, 2, 3, 4, 5};
}
int main() {
auto ov1 = std::views::all(f());
for (int n : ov1) {
std::cout << n; // 12345
}
std::cout << '\n';
// パイプラインスタイル(こう書いた時でも安全)
auto ov2 = f() | std::views::all;
for (int n : ov2) {
std::cout << n; // 12345
}
}
これはref_view
と共有しています。ref_view
は右辺値範囲を参照できないため、views::all
に右辺値範囲が渡された時はowning_view
が得られます。
とはいえ、パイプラインで他のview
を使用する際は、他のview
が入力範囲を自動でviews::all
に通してから保持するため、明示的にviews::all
を使用する必要はないでしょう(これはref_view
にもいえます)。
view
とowning_view
とC++20
このowning_view
はref_view
と値カテゴリに関して対になるものですが、当初のC++20には存在していませんでした。
C++20規格(N4861)完成の2020年4月から1年半後の2021年10月、view
の定義を再考する「P2415R2 What is a view?」がC++20に向けて採択されました(?)。これによって、view
の意味論要件が変更され(O(1)
で破棄可能という要件が緩和され)、限定的ながら範囲を所有するタイプのview
が実装可能となり、同時にviews::all
を右辺値に対して安全にするためにこのowning_view
が導入されました。
C++20規格完成から1年半後にC++20に対して追加されたので、規格書に載っておらず、それをベースとして書かれた解説やリファレンスにも記載が無かったりしますが、owning_view
はC++20のライブラリ機能です。
Discussion