⛓️
[C++] <ranges>のviewを見る9 - take_while_view
take_while_view
take_while_view
は元となるシーケンスから指定された条件を満たす連続要素によるシーケンスを生成するViewです。
#include <ranges>
int main() {
// 先頭から7未満の要素だけを取り出す
std::ranges::take_while_view tv{std::views::iota(1), [](int n) { return n < 7; }};
for (int n : tv) {
std::cout << n; // 123456
}
}
元となるシーケンスの先頭から条件を満たさない最初の要素の一つ前までのシーケンスを生成します。
take_while_view
は元となるrangeの性質をそのまま受け継ぎ(というかイテレータをそのまま利用し)、元となるrangeと同じカテゴリになります。
遅延評価
take_while_view
もまた、遅延評価によってシーケンスを生成します。ただ、take_while_view
は元となるrangeの極々薄いラッパーなので、ほとんどの操作はベースにあるイテレータの操作をそのまま呼び出すだけで、特別な事は行ないません。
take_while_view
が行なっている事は終端の管理だけで、==
による終端チェックのタイミングで現在の要素が条件を満たすか否かをチェックします。また、同時に現在の位置が元のシーケンスの終端に到達しているかもチェックすることでオーバーランを防止します。
// take_while_view構築時には何もしない
std::ranges::take_while_view tv{std::views::iota(1), [](int n) { return n < 7; }};
// イテレータ取得時には元のイテレータをそのまま返す
auto it = std::ranges::begin(tv);
// インクリメントは元のイテレータのインクリメント
++it;
// 間接参照も元のイテレータの間接参照
int n1 = *it; // n1 == 2
// 受け取った述語オブジェクトを私て番兵を構築する
auto fin = std::ranges::end(tv);
// 終端チェック時に現在のイテレータの指す要素が与えられた条件を満たしているかをチェック
// 同時に元のシーケンスの終端に到達しているかもチェックする
it == fin;
この特性上、==
による終端チェック時には毎回要素の参照と条件のチェックが行われます。条件判定にはあまり重い処理を渡さないように気を付けましょう。
views::take_while
take_while_view
に対応するrange adaptor objectがstd::views::take_while
です。
#include <ranges>
int main() {
for (int n : std::views::take_while(std::views::iota(1), [](int n) { return n < 7; })) {
std::cout << n; // 123456
}
std::cout << '\n';
// パイプラインスタイル
for (int n : std::views::iota(1) | std::views::take_while([](int n) { return n < 7; })) {
std::cout << n; // 123456
}
}
views::take_while
はカスタマイゼーションポイントオブジェクトであり、2つの引数を受け取りそれらを転送してtake_while_view
を構築して返します。
Discussion