Conversation
|
Template parameter names imply that this algorithm operates on a range of output iterators. But there's no such thing. Output iterators aren't required to have equality comparison. The algorithm actually requires a range of forward iterators. Also is it really a major improvement over the following? std::generate(first, last, [&init, op]{ return init = op(init); }) |
|
Hi @grisumbras - thanks for the feedback! I appreciate your concerns and I'd love to arrive at a design that you think is better 🙂
I used
It seems like there is no clear practice that's being followed throughout the codebase. I would argue that the type of iterator should be checked by the interface, not simply held in the name. To that end - does a boost wrapper around the iterator concepts exist? They could be added as constraints and checked where available.
I'll start by stating that that's a matter of opinion, but I would argue that it is an improvement. This library explicitly targets C++03 where lambdas aren't available - it's a clear win over writing a function object in that case. Even in standards where lambdas exist though, for me this API more clearly captures intent than |
|
A few observations:
The question "is iterate preferable to generate?" has a similar flavour to the question "is accumulate preferable to for_each?" In both cases the same effect as the "dedicated" function can be achieved with the "more general" function and stateful lambda expressions. But I consider both accumulate and iterate to be important upgrades in intent and in composability. Both also allow a more declarative coding style. iterate is an unfold, just as accumulate is a fold, and comparing iterate to accumulate (and contrasting with generate/for_each) is useful. iterate wins over generate in a couple of important ways:
One last thing: the name iterate is taken from Haskell. I haven't conducted a survey of other languages to see what the prevailing name of least surprise, if any, would be. |
The pattern is evidently that the name of the template parameter type corresponds to the named requirement. And regardless, using With regards to the name of the functions. |
|
I was misunderstanding the concern on iterator requirements - I've updated that to a state that I think is correct.
I have not been able to find a boost macro for move, unfortunately. If one exists, I'll happily pepper it throughout as I agree that that makes the behavior more flexible.
No - just a code style I've been trying out. (Roughly, the idea is that if prefix
I did some digging on this and couldn't find any other languages with similar named facilities where it wasn't called |
Problem: - There is no algorithm that generalizes `std::iota`. Filling a range 2 elements at a time is hard, more complex patterns are increasingly difficult. Solution: - Implement `iterate` and `iterate_n` which fill a range based on the execution of a binary operation which takes the previous value.
|
An update on the naming: As far as I can tell, this algorithm is only named in functional language standard libraries. Haskell, Clojure, OCaml, and Scala (and perhaps more, those were the ones that I found) have this algorithm and all of them call it |
Problem:
std::iota. Filling a range 2elements at a time is hard, more complex patterns are increasingly
difficult.
Solution:
Implement
iterateanditerate_nwhich fill a range based on theexecution of a binary operation which takes the previous value.
h/t to @elbeno for suggesting the algorithm and some feedback on the interface