Search code examples
c++templatesc++17rvalue-referenceperfect-forwarding

In standard algorithms, why are some template parameters rvalue references while others are not?


For example, let's take a look at the signature of std::reduce():

template< class ExecutionPolicy, class ForwardIt, class T, class BinaryOp >
T reduce( ExecutionPolicy&& policy,
          ForwardIt first, ForwardIt last, T init, BinaryOp binary_op );

The only parameter with && is policy, while the other parameters are supposed to be copied by value. I would understand if all the parameters were forward references, because I could imagine a heavy custom-made iterator that is hard to copy, as well as the initial value or functor of a big type. But why does only the execution policy have &&?


Solution

  • Iterators are always assumed to be reasonably inexpensive to copy. Algorithms are given wide latitude to copy iterators as much as they see fit (though I believe C++23 adds the ability to make move-only iterators, so for algorithms that can work with them, they are only allowed to move them), and many implementations take advantage of that. So using an iterator type that is "hard to copy" would always pose problems.

    The same goes for callable objects. These are presumed to be fairly trivial in size and contents, with algorithms being able to copy them as they see fit.

    reduce is going to call binary_op with two T values and assign this to its internal T. That's going to perform at least one copy. And it will do this N-1 times, where N is the number of elements in the sequence. Then it's going to return that value, also by value.

    So one more copy won't be noticed.