⛓️

[C++] <ranges>のviewを見る2 - single_view

2020/10/15に公開

single_view

single_view<T>は型Tの要素を1つだけ持つシーケンスを作成するViewです。

#include <ranges>

int main() {
  std::ranges::single_view<int> sv{20};

  for (int n : sv) {
    std::cout << n; // 1度だけ呼ばれる
  }
}

これもまたrangeを取るアルゴリズムに対してあえて1要素のrangeを入れたい場合など、1要素シーケンスが欲しい時に活用できるでしょう。

これは次のように定義されます。

namespace std::ranges {
  template<copy_constructible T>
    requires is_object_v<T>
  class single_view : public view_interface<single_view<T>> {
  private:
    semiregular-box<T> value_;  // 説明専用メンバ変数
  public:
    single_view() = default;
    constexpr explicit single_view(const T& t);
    constexpr explicit single_view(T&& t);
    template<class... Args>
      requires constructible_from<T, Args...>
    constexpr single_view(in_place_t, Args&&... args);

    constexpr T* begin() noexcept;
    constexpr const T* begin() const noexcept;
    constexpr T* end() noexcept;
    constexpr const T* end() const noexcept;
    static constexpr size_t size() noexcept;
    constexpr T* data() noexcept;
    constexpr const T* data() const noexcept;
  };
}

single_viewもまた、contiguous range(イテレータがcontiguous iteratorの範囲)です。

4つ目のコンストラクタはTのオブジェクトを内部でin place構築するためのものです。args...にコンストラクタ引数を渡す事で、直接コンストラクタを呼んで構築することができます。

int main() {
  
  // std::stringのコンストラクタを呼び出してもらう
  std::ranges::single_view<std::string> sv(std::in_place, "in place construct", 8);

  for (auto& str : sv) {
    std::cout << str; // in place
  }
}

range factories

single_viewにもrange factoryとなる関数オブジェクトが用意されています。これを用いると幾分か記述を省略できます。

int main() {
  for (auto& str : std::views::single(std::string{"in place construct", 8})) {
    std::cout << str;
  }
}

このstd::view::singleはカスタマイゼーションポイントオブジェクトであり、std::view::single(arg)のように呼び出すとstd::ranges::single_view{arg}を構築して返してくれます(無論、引数は完全転送されます)。
ただし、このCPOは1引数しか受け付けないため、in placeコンストラクタを呼び出すことはできません。

Discussion