13

I'm dealing with the last big 4 of C++ 20, attempting to learn the new main features. Trying some code from the web related to ranges, I've written:

std::vector ints{ 6, 5, 2, 8 };
auto even = [](int i) {
    return 0 == i % 2;
};

// ranges...
auto rr = ints | std::views::filter(even) 
               | std::views::transform([](auto i) {
                   return i * i;
                 })
               | std::views::reverse;

Then I would sort, like range-v3 does with |action::sort, but I've understand that this implementation is not the same.

The way I've found to sort is:

ints = std::vector(std::ranges::begin(rr), std::ranges::end(rr));
std::ranges::sort(ints);

Am I wrong? Does anybody know how to sort with pipe style the view ?

cigien
  • 57,834
  • 11
  • 73
  • 112
Chris
  • 277
  • 4
  • 15
  • 9
    @BitTickler The `|` was chosen for the analogy with unix pipes, I believe (and is very natural for people used to that environment). What do you mean by short-circuiting for bitwise-and anyway? – cigien Sep 28 '20 at 13:15
  • 1
    @BitTickler The `|` syntax comes from [boost::range](https://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/adaptors/introduction.html), circa 2010 – Caleth Sep 28 '20 at 15:10
  • 1
    @BitTickler `&` does not have short circuit semantics. – Barry Sep 28 '20 at 16:19
  • Okay - I concede that `&` would be just as bad as `|`. But the argument, that some OS has command line shells with a similar symbol is a weak argument, IMHO, because C++ programmers come from all walks of life. And either there is or there will be next year or the year after some programming language or environment which uses | as a comment... But for C/C++ people, `&` and `|` already have a fixed meaning. Also, I think this feature should come with compiler support (loop folding) and as such, it could get its own new syntax. – BitTickler Sep 28 '20 at 17:15
  • @BitTickler It's hard to imagine someone who is working with a somewhat low level language like C++ that has never used a Unix-based operating system or who doesn't know what piping is. I'd guesstimate 95% of employed programmers are familiar with the syntax automatically. – user904963 Mar 12 '22 at 01:31
  • @Caleth It's from Unix-based operating systems circa 1971. Boost took it from there. – user904963 Mar 12 '22 at 01:32
  • @user904963 Haskell uses `.` for (reverse) piping/composition, F# uses `|>`, so does Julia, Ocaml, .... In C++ something like piping already exists (iostreams, using `>>`) and I guess the list could be extended ad infinitum. The "boost did it that way" argument is also weak, because boost authors have to use what the language gives them - but a new compiler supported version of C++ has many more degrees of freedom to choose. And please note, that DOS ever since it came to be uses `&` and I guess more installations exist(ed) for DOS/WINDOWS than for unixes :) – BitTickler Mar 12 '22 at 02:34
  • @BitTickler `.` is a function composition operator. While similar, it makes the flow opposite to piping. `|>` is very close to `|`, so it's odd to talk about it like it's a brand new operator with zero connection to Unix. `>>` is an overloaded operator that signifies, for streams, that something will be "read" from it. It's not as general as a pipe that feeds output directly into the input of something else. The DOS command is about executing commands serially, not piping output from one command to another command. Seriously though, people study computer science on Linux. `|` = good call. – user904963 Mar 12 '22 at 03:41
  • FWIW. DOS got pipes '|' (borrowed from Unix) in 1983. MacOS didn't have a (builtin) command-line prompt until X (2001), which had bash. – Spongman Jan 26 '23 at 22:39

1 Answers1

11

Then I would sort, like range-v3 does with |action::sort ...

No, you can't actually sort rr like this:

rr |= ranges::actions::sort; // error

because rr is a view. While views can provide mutable access to the underlying range, sort additionally needs the range to support random access. A lazily generated view like rr does not allow this.

You can create a vector from rr as you have done, and then you can use actions on that range:

ints |= ranges::actions::sort;  // ok

c++20, however, doesn't have any actions (hopefully we'll get them in c++23), so until then you'll have to call the algorithm sort without the pipe syntax:

std::ranges::sort(ints);  // ok
cigien
  • 57,834
  • 11
  • 73
  • 112
  • `view`s can be modifiable. – Barry Sep 28 '20 at 16:20
  • @Barry Oh, how so? I thought `view`s were like `span` in that it doesn't own the underlying range, but unlike `span`, that `view`s don't allow modifying the range either. – cigien Sep 28 '20 at 16:22
  • Non-owning (`views::single` notwithstanding) yes, but they can provide mutable access. `span` is just as much a view as `span` is. – Barry Sep 28 '20 at 16:30
  • @Barry Ok, that makes sense. I reworded the answer, is this better? – cigien Sep 28 '20 at 16:53
  • 1
    Right, the issue here has nothing to do with views. You can `sort` a `view` - it's just that `sort` requires random access, and that gets lost with the `filter` (and also you can't `sort` a range of prvalues). – Barry Sep 28 '20 at 17:55
  • @Barry Ok, so the answer is clear enough. Would the random access property get lost with `reverse` as well? I think transform should be ok though. – cigien Sep 28 '20 at 17:58
  • 2
    Reversing a random access iterator still gives you a random access iterator, that part is fine. `transform` gives you a prvalue, which makes things non-sortable, but if it gave an lvalue, that'd be fine. e.g. `sort(iota(0u, v.size()) | transform([&v](int i) -> int& { return v[i]; }));` is a valid, if ridiculous, way to do `sort(v);` – Barry Sep 28 '20 at 18:08