c++c++17stl-algorithm

Do the unseq execution policy require the iterators' value_type to be Cpp17CopyAssignable?


The following snipped does not compile with GCC 10 (Compiler Explorer link):

#include <vector>
#include <algorithm>
#include <execution>

struct T
{
  int const ID; // Not Cpp17CopyAssignable
};

int f(std::vector<T> const &v)
{
  if (v.empty()) return -1;
  
  return std::min_element(std::execution::par_unseq, v.begin(), v.end(),
                          [](T const &lhs, T const &rhs) { return lhs.ID < rhs.ID; })->ID;
}

because T is not Cpp17CopyAssignable:

 error: use of deleted function 'T& T::operator=(const T&)'
  643 |                 __min_val = __obj.__min_val;
      |                 ~~~~~~~~~~^~~~~~~~~~~~~~~~~

I cannot find such requirement in either cppreference or [algorithms]. Did I miss it?


Solution

  • The C++ standard doesn't require values of the sequence passed to a parallel algorithm to be assignable (nor copy-constructible, nor default-constructible) unless required by the non-parallel counterpart. An implementation that doesn't accept such values is non-conforming.

    [algorithms.parallel.defns]/2 Parallel algorithms access objects indirectly accessible via their arguments by invoking the following functions:
    ...
    (2.2) — Operations on those sequence elements that are required by its specification.
    ...

    This says the algorithm shouldn't demand more than is necessary from the value type.

    Parallel algorithms are allowed to make copies of elements sometimes:

    [algorithms.parallel.exec]/2 Unless otherwise stated, implementations may make arbitrary copies of elements (with type T) from sequences where is_trivially_copy_constructible_v<T> and is_trivially_destructible_v<T> are true.

    But only for those elements that are trivially copy constructible, and then by copy constructor, not by assignment.