[PATCH] D33997: Implement the non-execution policy versions of `reduce` and `transform_reduce` for C++17

Bryce Adelstein Lelbach via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 8 12:36:15 PDT 2017


wash added a comment.

Suppose you have:

  struct A {};
  struct B {};
  
  A operator+(A, B);
  
  std::vector<B> v;
  std::reduce(v.begin(), v.end(), A{});

The implementation in this patch works fine for the above case - as would `accumulate`, which it is equivalent to. However, `reduce` requires that "All of `binary_op(init, *first)`, `binary_op(*first, init)`, `binary_op(init, init)`, and `binary_op(*first, *first)` shall be convertible to T.", as all those operations may be needed for the parallel execution-policy overload of `reduce` (the requirement applies to the non-execution-policy overload as well).

E.g. in the above example, these operations are also required by `reduce`, even though the non-parallel implementation does not need them:

  A operator+(B, A);
  A operator+(A, A);
  A operator+(B, B);

Should the non-parallel implementation of `reduce` static_assert or SFINAE away when these requirements are not met? I think it might be desirable to ensure that if this won't compile:

  std::reduce(std::par, v.begin(), v.end(), A{});

Then this will also not compile:

  std::reduce(v.begin(), v.end(), A{});

(And the spec seems to suggest this too).



================
Comment at: include/numeric:154
+    return reduce(__first, __last, 
+       typename iterator_traits<_InputIterator>::value_type{}, _VSTD::plus<>());
+}
----------------
In the spec, this overload of `reduce` is described as equivalent to `return reduce(std::forward<ExecutionPolicy>(exec), first, last, typename iterator_traits<ForwardIterator>::value_type{});`.  The overload that it calls (the three argument version that omits a binary operation) just forwards to the four-argument reduce, adding the `plus<>()` argument.

Is there a reason you wanted to avoid the extra layer of function call indirection (it should be inlined and optimized away, right)? What you have seems perfectly fine, I'm just curious though.


================
Comment at: test/std/numerics/numeric.ops/reduce/reduce_iter_iter.pass.cpp:37
+    unsigned sa = sizeof(ia) / sizeof(ia[0]);
+    test(Iter(ia), Iter(ia), 0);
+    test(Iter(ia), Iter(ia+1), 1);
----------------
 Just to confirm, this should be 0 because the "default" init value is `iterator_traits<_InputIterator>::value_type{}`, and `int{}` gives you a determinate result (as opposed to `int()` which would not), correct?


https://reviews.llvm.org/D33997





More information about the cfe-commits mailing list