I'm currently trying to wrap my head around the upcoming std::ranges. As an exercise I'd like to implement a "toupper" view from scratch which takes a range/view over some characters and transforms those to upper case.
Hacking together a view and some iterator was pretty straight forward, I don't get how operator() and | have to be overloaded in order to compose like the rest of ranges does though.
Here is the "toupper_fn" (to follow the ranges naming convention) I came up with so far. This is pretty much a copy/paste of some view function inside the ranges 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));
}
};
The problem is that with those definitions both, the classic function call syntax (view(view...)) and the pipe syntax, only work if my own view is the last in the chain.
Here is the whole code on godbolt ->
Either with ranges-v3: https://godbolt.org/z/6RlNVC
Or cmcstl2: https://godbolt.org/z/wba_yW