3355. The memory algorithms should support move-only input iterators introduced by P1207

Section: 26.11.5 [uninitialized.copy], 26.11.6 [uninitialized.move] Status: C++20 Submitter: Corentin Jabot Opened: 2019-11-12 Last modified: 2021-02-25

Priority: 2

View all other issues in [uninitialized.copy].

View all issues with C++20 status.

Discussion:

P1207 introduced move-only input iterators but did not modify the specialized memory algorithms to support them.

[2020-01 Priority set to 2 after review on the reflector.]

[2020-02 Status to Immediate on Friday morning in Prague.]

Proposed resolution:

This wording is relative to N4842.

  1. Modify 26.11.5 [uninitialized.copy] as indicated:

    namespace ranges {
      template<input_iterator I, sentinel_for<I> S1,
               no-throw-forward-iterator O, no-throw-sentinel<O> S2>
          requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
        uninitialized_copy_result<I, O>
          uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast);
      template<input_range IR, no-throw-forward-range OR>
          requires constructible_from<range_value_t<OR>, range_reference_t<IR>>
        uninitialized_copy_result<safe_iterator_t<IR>, safe_iterator_t<OR>>
          uninitialized_copy(IR&& in_range, OR&& out_range);
    }
    

    -4- Preconditions: [ofirst, olast) shall not overlap with [ifirst, ilast).

    -5- Effects: Equivalent to:

    for (; ifirst != ilast && ofirst != olast; ++ofirst, (void)++ifirst) {
      ::new (voidify(*ofirst)) remove_reference_t<iter_reference_t<O>>(*ifirst);
    }
    return {std::move(ifirst), ofirst};
    

    […]
    namespace ranges {
      template<input_iterator I, no-throw-forward-iterator O, no-throw-sentinel<O> S>
          requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
        uninitialized_copy_n_result<I, O>
          uninitialized_copy_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast);
    }
    

    -9- Preconditions: [ofirst, olast) shall not overlap with [ifirst, n).

    -10- Effects: Equivalent to:

    auto t = uninitialized_copy(counted_iterator(ifirst, n),
                                default_sentinel, ofirst, olast);
    return {std::move(t.in).base(), t.out};
    

  2. Modify 26.11.6 [uninitialized.move] as indicated:

    namespace ranges {
      template<input_iterator I, sentinel_for<I> S1,
               no-throw-forward-iterator O, no-throw-sentinel<O> S2>
          requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
        uninitialized_move_result<I, O>
          uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast);
      template<input_range IR, no-throw-forward-range OR>
          requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
        uninitialized_move_result<safe_iterator_t<IR>, safe_iterator_t<OR>>
          uninitialized_move(IR&& in_range, OR&& out_range);
    }
    

    -3- Preconditions: [ofirst, olast) shall not overlap with [ifirst, ilast).

    -4- Effects: Equivalent to:

    for (; ifirst != ilast && ofirst != olast; ++ofirst, (void)++ifirst) {
      ::new (voidify(*ofirst)) 
        remove_reference_t<iter_reference_t<O>>(ranges::iter_move(*ifirst));
    }
    return {std::move(ifirst), ofirst};
    

    […]
    namespace ranges {
      template<input_iterator I, no-throw-forward-iterator O, no-throw-sentinel<O> S>
          requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
        uninitialized_move_n_result<I, O>
          uninitialized_move_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast);
    }
    

    -8- Preconditions: [ofirst, olast) shall not overlap with [ifirst, n).

    -9- Effects: Equivalent to:

    auto t = uninitialized_move(counted_iterator(ifirst, n),
                                default_sentinel, ofirst, olast);
    return {std::move(t.in).base(), t.out};