3222. P0574R1 introduced preconditions on non-existent parameters

Section: 26.10.9 [inclusive.scan], 26.10.11 [transform.inclusive.scan] Status: C++20 Submitter: Jonathan Wakely Opened: 2019-06-18 Last modified: 2021-02-25

Priority: 0

View all issues with C++20 status.

Discussion:

after applying P0574R1 to the working draft, 26.10.11 [transform.inclusive.scan] bullet 1.1 says "If init is provided, […]; otherwise, ForwardIterator1's value type shall be […]." 26.10.11 [transform.inclusive.scan] bullet 1.2 says "If init is provided, […]; otherwise, […] shall be convertible to ForwardIterator1's value type."

For the first overload init is not provided, but there is no ForwardIterator1, so these requirements cannot be met. The requirements for the first overload need to be stated in terms of InputIterator's value type, not ForwardIterator1's value type.

The same problem exists in 26.10.9 [inclusive.scan]. 26.10.12 [adjacent.difference] solves this problem by saying "Let T be the value type of decltype(first)".

[2019-07 Issue Prioritization]

Status to Tentatively Ready after five positive votes on the reflector.

Proposed resolution:

This wording is relative to N4820.

  1. Modify 26.10.9 [inclusive.scan] as indicated:

    template<class InputIterator, class OutputIterator, class BinaryOperation>
      OutputIterator inclusive_scan(InputIterator first, InputIterator last,
                                    OutputIterator result, BinaryOperation binary_op);
    template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
             class BinaryOperation>
      ForwardIterator2 inclusive_scan(ExecutionPolicy&& exec,
                                      ForwardIterator1 first, ForwardIterator1 last,
                                      ForwardIterator2 result, BinaryOperation binary_op);
    template<class InputIterator, class OutputIterator, class BinaryOperation, class T>
      OutputIterator inclusive_scan(InputIterator first, InputIterator last,
                                    OutputIterator result, BinaryOperation binary_op, T init);
    template<class ExecutionPolicy,
             class ForwardIterator1, class ForwardIterator2, class BinaryOperation, class T>
      ForwardIterator2 inclusive_scan(ExecutionPolicy&& exec,
                                      ForwardIterator1 first, ForwardIterator1 last,
                                      ForwardIterator2 result, BinaryOperation binary_op, T init);
    

    -?- Let U be the value type of decltype(first).

    -3- Requires:

    1. (3.1) — If init is provided, T shall be Cpp17MoveConstructible (Table 26); otherwise, ForwardIterator1's value typeU shall be Cpp17MoveConstructible.

    2. (3.2) — If init is provided, all of binary_op(init, init), binary_op(init, *first), and binary_op(*first, *first) shall be convertible to T; otherwise, binary_op(*first, *first) shall be convertible to ForwardIterator1's value typeU.

    3. (3.3) — binary_op shall neither invalidate iterators or subranges, nor modify elements in the ranges [first, last] or [result, result + (last - first)].

  2. Modify 26.10.11 [transform.inclusive.scan] as indicated:

    template<class InputIterator, class OutputIterator,
             class BinaryOperation, class UnaryOperation>
      OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last,
                                              OutputIterator result,
                                              BinaryOperation binary_op, UnaryOperation unary_op);
    template<class ExecutionPolicy,
             class ForwardIterator1, class ForwardIterator2,
             class BinaryOperation, class UnaryOperation>
      ForwardIterator2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                                ForwardIterator1 first, ForwardIterator1 last,
                                                ForwardIterator2 result,
                                                BinaryOperation binary_op, UnaryOperation unary_op);
    template<class InputIterator, class OutputIterator,
             class BinaryOperation, class UnaryOperation, class T>
      OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last,
                                              OutputIterator result,
                                              BinaryOperation binary_op, UnaryOperation unary_op,
                                              T init);
    template<class ExecutionPolicy,
             class ForwardIterator1, class ForwardIterator2,
             class BinaryOperation, class UnaryOperation, class T>
      ForwardIterator2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                                ForwardIterator1 first, ForwardIterator1 last,
                                                ForwardIterator2 result,
                                                BinaryOperation binary_op, UnaryOperation unary_op,
                                                T init);
    

    -?- Let U be the value type of decltype(first).

    -1- Requires:

    1. (1.1) — If init is provided, T shall be Cpp17MoveConstructible (Table 26); otherwise, ForwardIterator1's value typeU shall be Cpp17MoveConstructible.

    2. (1.2) — If init is provided, all of

      1. (1.2.1) — binary_op(init, init),

      2. (1.2.2) — binary_op(init, unary_op(*first)), and

      3. (1.2.3) — binary_op(unary_op(*first), unary_op(*first))

      shall be convertible to T; otherwise, binary_op(unary_op(*first), unary_op(*first)) shall be convertible to ForwardIterator1's value typeU.

    3. (1.3) — Neither unary_op nor binary_op shall invalidate iterators or subranges, nor modify elements in the ranges [first, last] or [result, result + (last - first)].