I've written an answer here: https://stackoverflow.com/a/44481507/2642059 which uses accumulate
.
The functor must be binary with a signature like: Ret op(const auto& a, const auto& b)
but:
The signature does not need to have
const &
The requirement on the binary functor is that it:
Must not invalidate any iterators, including the end iterators, or modify any elements of the range involved
When the object accumulated into is itself a container, I'm a unclear as to the requirements on the functor. For example is something like this allowed?
const auto range = { 0, 1, 2, 3 };
const auto Ret = accumulate(cbegin(range), cend(range), vector<int>(), [](auto& a, const auto& b){
a.push_back(b);
return a;
});
Yes, I recognize this is just a copy, I'm not asking for a better solution I'm asking about the validity of this solution.
I think the working draft is more explicit than cppreference or whatever:
In the range
[first, last]
,binary_op
shall neither modify elements nor invalidate iterators or subranges.
Where accumulate
is declared as:
template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);
template <class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op);
Therefore I would say that your example is valid, for you are not affecting the range [first, last]
.
On the other side, the constraint makes perfectly sense for the given range, for you define it with a couple of iterators.
As an example think of what would happen if they were begin and end iterators of a vector at the end of which you decide to push values within binary_op
.
As soon as the vector resizes, accumulate
goes on working with a couple of dangling pointers. No good.