Search code examples
c++language-lawyerfunctoraccumulatebinary-operators

What are the Requirements on accumulate's Functor?


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.


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.