⛓️

[C++] <ranges>のviewを見る11 - drop_while_view

2020/10/22に公開

drop_while_view

drop_while_viewは元となるシーケンスの先頭から条件を満たす連続した要素を取り除いたシーケンスを生成するViewです。

#include <ranges>

iint main() {
  // 先頭のホワイトスペースを取り除く
  std::ranges::drop_while_view dv{"     drop while view", [](char c) { return c == ' '; }};
  
  for (char c : dv) {
    std::cout << c;
  }
}

drop_while_viewはかなりdrop_viewと似た振る舞いをします。

オーバーラン防止と遅延評価

drop_while_viewdrop_viewと同様の方法によって遅延評価とオーバーランの防止を行なっています。

すなわち、drop_while_viewはそのイテレータの取得時(begin()の呼び出し時)に元となるシーケンスの先頭イテレータを条件を満たさない最初の要素まで進めて返します。その際、元のシーケンス上で終端チェックを行いながら進めることでオーバーランしないようになっています。これはC++20から追加されたstd::ranges::find_if_not(base_view, pred)を使用して行われます。

// drop_view構築時にはまだ何もしない
std::ranges::drop_while_view dv{"     drop while view", [](char c) { return c == ' '; }};

// イテレータ取得時にスキップ処理が行われる
// 元のシーケンスの先頭イテレータを条件を満たす間進めるだけ
// その際終端チェックを同時に行う
auto it = std::ranges::begin(dv);

// その他の操作は元のシーケンスのイテレータそのまま
++it;
*it;

drop_while_viewは元となるシーケンスのイテレータを完全に流用するので、drop_while_viewrangeは元のシーケンスのrangeカテゴリと同じになります。

drop_while_viewbegin()の呼び出しも、元のシーケンスがforward_range(以上の強さ)であるときキャッシュされることが規定されています。これによってdrop_while_viewbegin()も計算量は償却定数となります。

views::drop_while

drop_while_viewに対応するrange adaptor objectstd::views::drop_whileです。

#include <ranges>

int main() {
  for (char c : std::views::drop_while("     drop while view", [](char c) { return c == ' '; })) {
    std::cout << c;
  }
  
  std::cout << '\n';

  // パイプラインスタイル
  for (char c : "     drop while view" | std::views::drop_while([](char c) { return c == ' '; })) {
    std::cout << c;
  }
}

views::drop_whileはカスタマイゼーションポイントオブジェクトであり、2つの引数を受け取りそれらを転送してdrop_while_viewを構築して返します。

Discussion