It seems that the algorithms in ranges v3 aren't chainable, i.e:
const auto ints = std::vector<int>{1,2,1,3,1,4,1,5,1,6};
const auto num_ones = ints | ranges::count(1);
... has to be written functional style:
const auto num_ones = ranges::count(ints, 1);
Is this a design choice that only algorithms/actions which returns a new range/container are pipeable?
The output of chained views must be another view (i.e. a range). That way, you can keep chaining the result using more views.
The result of
countis not a range, so it doesn't make sense to have that operation in the chain. In the hypothetical case that you were able to, you wouldn't be able to chain the result of that operation to another view.Viewing the situation from another angle, in range-v3 views are lazily evaluated. Counting the number of elements in a range is not a lazy operation, since it requires the entire range to be evaluated to get a result. It's a different kind of operation.
The same reasoning can be applied to the other "free-standing" algorithms, like
ranges::copy,ranges::sort,ranges::min_element, etc. Those should be seen as variants (or improvements) of the correspondingstdalgorithms, but that also accept ranges as arguments, instead of pairs of iterators.With that being said, some of the free-standing algorithms are also available as views, where it makes sense (like the
set_intersection,set_differenceandset_unionfamily of algorithms).Edit: There are exceptions to this rule. Namely, the functions
ranges::to_vectorandranges::to_, which "sink" the piped range into astd::vector(or a container of your choosing).