创建范围自定义视图函数(operator() 和operator|)

Vin*_*nci 5 c++ view range custom-view

我目前正在尝试了解即将到来的 std::ranges。作为练习,我想从头开始实现一个“toupper”视图,它对某些字符进行范围/视图并将其转换为大写。

将视图和一些迭代器组合在一起非常简单,我不明白如何操作符()和| 必须重载才能像其他范围一样进行组合。

这是我到目前为止想出的“toupper_fn”(遵循范围命名约定)。这几乎是 v3 范围内某些视图函数的复制/粘贴:

    struct toupper_fn {
      template <typename Rng>
      auto operator()(Rng&& rng) const {
        return toupper_view{std::forward<Rng>(rng)};
      }

      template <typename Rng>
      friend auto operator|(Rng&& rng, toupper_fn& c)
          -> decltype(c(std::forward<Rng>(rng))) {
        return c(std::forward<Rng>(rng));
      }

      template <typename Rng>
      friend auto operator|(Rng&& rng, toupper_fn const& c)
          -> decltype(c(std::forward<Rng>(rng))) {
        return c(std::forward<Rng>(rng));
      }

      template <typename Rng>
      friend auto operator|(Rng&& rng, toupper_fn&& c)
          -> decltype(std::move(c)(std::forward<Rng>(rng))) {
        return std::move(c)(std::forward<Rng>(rng));
      }
    };
Run Code Online (Sandbox Code Playgroud)

问题是,对于这些定义,经典函数调用语法 (view(view...)) 和管道语法,仅当我自己的视图是链中的最后一个时才有效。

这是 godbolt 上的完整代码 ->

使用 range-v3: https: //godbolt.org/z/6RlNVC

或 cmcstl2: https: //godbolt.org/z/wba_yW

Vin*_*nci 2

好吧,我想通了。初始代码的问题是我的自定义视图既不满足范围也不满足视图概念。那是因为我的迭代器缺少一些特征......

另外,将构造函数参数包装在 range::view::all 中以直接支持容器也是一个好主意。视图“all”根据其输入类型创建无操作、引用包装器或子范围。

这是修改后的工作版本: https ://godbolt.org/z/5YOGNW

/编辑

Chris Di Bella 在 CppCon2019 上的演讲稍微澄清了我答案的第二部分。但他没有包装构造函数参数,而是使用视图本身的推导指南,这当然是首选方式:

template<typename R>
toupper_view(R&&)->toupper_view<ranges::all_view<R>>; // or in ranges v3 -> ranges::cpp20::all_view
Run Code Online (Sandbox Code Playgroud)