This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of LEWG status.

3868. Constrained algorithms should not require output_iterator

Section: 26.7.5 [alg.replace], 26.7.6 [alg.fill] Status: LEWG Submitter: Hewill Kang Opened: 2023-01-29 Last modified: 2024-06-28

Priority: 4

View all other issues in [alg.replace].

View all issues with LEWG status.

Discussion:

In C++20, output_iterator is required to support *o++ = t mainly for backward compatibility, that is to say, in addition to avoiding needless breakage, this semantic is actually not very useful, as it can be equivalently replaced by *o = t; ++o;.

This is reflected in the current implementation for constrained algorithms in libstdc++ and MSVC-STL. Even if the algorithm explicitly requires output_iterator, there is no code of the form *o++ = t in practice, and the latter of a more generic form is used instead.

It seems to me that constrained algorithms should never require output_iterator, since there really isn't any desirable reason to use *o++ = t in the new iterator system. It would be more appropriate to relax output_iterator to weakly_incrementable (or input_or_output_iterator) and indirectly_writable, given that many constrained algorithms already do that.

[2023-02-06; Reflector poll]

Set priority to 4 after reflector poll. Send to LEWG. Several votes for NAD.

[St. Louis 2024-06-28; LWG and SG9 joint session]

Poll: SG9 and LWG believe this is not a defect, but we do agree that there are inconsistencies that need a paper to address more thoroughly

|SF| F| N| A|SA|
| 6| 2| 0| 0| 0|

Proposed resolution:

This wording is relative to N4928.

  1. Modify 26.4 [algorithm.syn], header <algorithm> synopsis, as indicated:

    #include <initializer_list>     // see 17.10.2 [initializer.list.syn]
    
    namespace std {
      […]
      namespace ranges {
        template<class I, class O>
          using replace_copy_result = in_out_result<I, O>;
    
        template<input_iterator I, sentinel_for<I> S, class T1, class T2,
                 weakly_incrementableoutput_iterator<const T2&> O, class Proj = identity>
          requires indirectly_writable<O, const T2&> && indirectly_copyable<I, O> &&
                   indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
          constexpr replace_copy_result<I, O>
            replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
                         Proj proj = {});
        template<input_range R, class T1, class T2, weakly_incrementableoutput_iterator<const T2&> O,
                 class Proj = identity>
          requires indirectly_writable<O, const T2&> && indirectly_copyable<iterator_t<R>, O> &&
                   indirect_binary_predicate<ranges::equal_to,
                                             projected<iterator_t<R>, Proj>, const T1*>
          constexpr replace_copy_result<borrowed_iterator_t<R>, O>
            replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
                         Proj proj = {});
    
        template<class I, class O>
          using replace_copy_if_result = in_out_result<I, O>;
    
        template<input_iterator I, sentinel_for<I> S, class T, weakly_incrementableoutput_iterator<const T&> O,
                 class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
          requires indirectly_writable<O, const T&> && indirectly_copyable<I, O>
          constexpr replace_copy_if_result<I, O>
            replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
                            Proj proj = {});
        template<input_range R, class T, weakly_incrementableoutput_iterator<const T&> O, class Proj = identity,
                 indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
          requires indirectly_writable<O, const T&> && indirectly_copyable<iterator_t<R>, O>
          constexpr replace_copy_if_result<borrowed_iterator_t<R>, O>
            replace_copy_if(R&& r, O result, Pred pred, const T& new_value,
                            Proj proj = {});
      }
      […]
      namespace ranges {
        template<class T, input_or_output_iteratoroutput_iterator<const T&> O, sentinel_for<O> S>
          requires indirectly_writable<O, const T&>
          constexpr O fill(O first, S last, const T& value);
        template<class T, output_range<const T&> R>
          constexpr borrowed_iterator_t<R> fill(R&& r, const T& value);
        template<class T, input_or_output_iteratoroutput_iterator<const T&> O>
          requires indirectly_writable<O, const T&>
          constexpr O fill_n(O first, iter_difference_t<O> n, const T& value);
      }
      […]
    }
    
  2. Modify 26.7.5 [alg.replace] as indicated:

    […]
    template<input_iterator I, sentinel_for<I> S, class T1, class T2, weakly_incrementableoutput_iterator<const T2&> O, 
             class Proj = identity>
      requires indirectly_writable<O, const T2&> && indirectly_copyable<I, O> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
    constexpr ranges::replace_copy_result<I, O>
      ranges::replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
                           Proj proj = {});
    template<input_range R, class T1, class T2, weakly_incrementableoutput_iterator<const T2&> O,
             class Proj = identity>
      requires indirectly_writable<O, const T2&> && indirectly_copyable<iterator_t<R>, O> &&
               indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T1*>
    constexpr ranges::replace_copy_result<borrowed_iterator_t<R>, O>
      ranges::replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
                           Proj proj = {});
    
    template<input_iterator I, sentinel_for<I> S, class T, weakly_incrementableoutput_iterator<const T&> O,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_writable<O, const T&> && indirectly_copyable<I, O>
    constexpr ranges::replace_copy_if_result<I, O>
      ranges::replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
                              Proj proj = {});
    template<input_range R, class T, weakly_incrementableoutput_iterator<const T&> O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_writable<O, const T&> && indirectly_copyable<iterator_t<R>, O>
    constexpr ranges::replace_copy_if_result<borrowed_iterator_t<R>, O>
      ranges::replace_copy_if(R&& r, O result, Pred pred, const T& new_value,
                              Proj proj = {});
    
    

    -6- Let E be

    […]

  3. Modify 26.7.6 [alg.fill] as indicated:

    […]
    template<class T, input_or_output_iteratoroutput_iterator<const T&> O, sentinel_for<O> S>
      requires indirectly_writable<O, const T&>
      constexpr O ranges::fill(O first, S last, const T& value);
    template<class T, output_range<const T&> R>
      constexpr borrowed_iterator_t<R> ranges::fill(R&& r, const T& value);
    template<class T, input_or_output_iteratoroutput_iterator<const T&> O>
      requires indirectly_writable<O, const T&>
      constexpr O ranges::fill_n(O first, iter_difference_t<O> n, const T& value);
    

    -1- Let N be max(0, n) for the fill_n algorithms, and last - first for the fill algorithms.

    […]

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy