Title
ranges::to should reserve when sized_sentinel_for is satisfied
Status
new
Section
[range.utility.conv.to]
Submitter
Hewill Kang

Created on 2024-04-13.00:00:00 last changed 2 days ago

Messages

Date: 2025-10-20.16:17:38

Proposed resolution:

This wording is relative to N5014.

  1. Modify [range.utility.conv.to] as indicated:

    template<class C, input_range R, class... Args> requires (!view<C>)
      constexpr C to(R&& r, Args&&... args);
    

    -1- Mandates: C is a cv-unqualified class type.

    -2- Returns: An object of type C constructed from the elements of r in the following manner:

    1. (2.1) — […]

      1. (2.1.1) — […]

      2. (2.1.2) — […]

      3. (2.1.3) — […]

      4. (2.1.4) — Otherwise, if

        1. (2.1.4.1) — constructible_from<C, Args...> is true, and

        2. (2.1.4.2) — container-appendable<C, range_reference_t<R>> is true:

          C c(std::forward<Args>(args)...);
          subrange s{r};
          if constexpr (sized_range<Rdecltype(s)> && reservable-container<C>)
            c.reserve(static_cast<range_size_t<C>>(ranges::size(r)s.size()));
          ranges::for_each(rs, container-append(c));
          
Date: 2025-10-15.00:00:00

[ 2025-10-20; Jonathan provides updated wording ]

Date: 2025-10-15.00:00:00

[ 2025-10-20; Reflector poll. ]

Set priority to 4 after reflector poll. Most votes were "P4 or NAD".

"I do not see a motivating example of `input_range` that would produce `sized_sentinel_for` for `begin`/`end` but would not be sized itself. However, the fix seems correct. Would prefer if would check if produced `subrange` is sized, instead of using a requires expression."

"Might as well do it, even though a `sized_sentinel_for`-but-not-sized input range feels like an extreme corner case."

"This is just applying the contrived case mentioned in LWG 3737 to `ranges::to`."

This wording is relative to N4981.

  1. Modify [range.utility.conv.to] as indicated:

    template<class C, input_range R, class... Args> requires (!view<C>)
      constexpr C to(R&& r, Args&&... args);
    

    -1- Mandates: C is a cv-unqualified class type.

    -2- Returns: An object of type C constructed from the elements of r in the following manner:

    1. (2.1) — […]

      1. (2.1.1) — […]

      2. (2.1.2) — […]

      3. (2.1.3) — […]

      4. (2.1.4) — Otherwise, if

        1. (2.1.4.1) — constructible_from<C, Args...> is true, and

        2. (2.1.4.2) — container-appendable<C, range_reference_t<R>> is true:

          C c(std::forward<Args>(args)...);
          subrange s{r};
          if constexpr (sized_range<R>requires { s.size(); } && reservable-container<C>)
            c.reserve(static_cast<range_size_t<C>>(ranges::size(r)s.size()));
          ranges::for_each(rs, container-append(c));
          
Date: 2025-02-15.00:00:00

[ 2025-02-27; post-Hagenberg status ]

The proposed resolution needs rebasing after P2846R6 was approved in Hagenberg. It also conflicts with LWG 3722.

Date: 2024-04-13.00:00:00

ranges::to currently only reserves when r satisfies sized_range. However, we can also extract its size when r is an input_range that its sentinel-iterator pair satisfies sized_sentinel_for.

Given that we have specifically designed the decision tree, I see no reason not to reserve in this case, since we'd be calling ranges::begin(r) anyway.

History
Date User Action Args
2025-10-20 16:17:38adminsetmessages: + msg15286
2025-10-20 16:17:38adminsetmessages: + msg15282
2025-02-27 16:29:19adminsetmessages: + msg14661
2024-04-14 08:49:20adminsetmessages: + msg14058
2024-04-13 00:00:00admincreate