我目前正在努力思考即将到来的 std::ranges。作为练习,我想从头开始实现一个“toupper” View ,它对某些字符进行范围/ View 并将它们转换为大写。
将一个 View 和一些迭代器组合在一起非常简单,我不明白 operator() 和 |必须重载才能像其余范围一样进行组合。
这是我到目前为止提出的“toupper_fn”(遵循范围命名约定)。这几乎是 v3 范围内某些 View 函数的复制/粘贴:
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));
}
};
问题在于,对于这些定义,经典函数调用语法 (view(view...)) 和管道语法,仅当我自己的 View 是链中的最后一个时才有效。
这是 Godbolt 上的全部代码 ->
范围-v3:https://godbolt.org/z/6RlNVC
或 cmcSTL2: https://godbolt.org/z/wba_yW
最佳答案
好吧,我明白了。初始代码的问题是我的自定义 View 既不满足范围也不满足 View 概念。那是因为我的迭代器缺少一些特征...
此外,将构造函数参数包装在 ranges::view::all 中以直接支持容器也是一个好主意。 View “all”根据其输入类型创建空操作、引用包装器或子范围。
这是修改后的工作版本: https://godbolt.org/z/5YOGNW
/编辑
A CppCon2019 talk by Chris Di Bella澄清了我的答案的第二部分。但是他没有包装构造函数参数,而是使用 View 本身的推导指南,这当然是首选方式:
template<typename R>
toupper_view(R&&)->toupper_view<ranges::all_view<R>>; // or in ranges v3 -> ranges::cpp20::all_view
关于c++ - 创建范围自定义 View 函数(operator() 和 operator|),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58029724/