3984. ranges::to's recursion branch may be ill-formed

Section: 25.5.7.2 [range.utility.conv.to] Status: WP Submitter: Hewill Kang Opened: 2023-08-23 Last modified: 2024-04-02

Priority: 3

View other active issues in [range.utility.conv.to].

View all other issues in [range.utility.conv.to].

View all issues with WP status.

Discussion:

When r is a nested range, ranges::to constructs the object recursively through r | views::transform(...).

However, the expression is ill-formed when the type of lvalue r does not model viewable_range (demo):

#include <ranges>
#include <vector>
#include <list>

int main() {
  std::vector<std::vector<int>> v;
  auto r = std::views::all(std::move(v));
  auto l = std::ranges::to<std::list<std::list<int>>>(r); // hard error in MSVC-STL and libc++
}

[2023-11-03; Reflector poll]

Set priority to 3 after reflector poll. "Should be std::forward<R>(r) instead?"

[Kona 2023-11-07; move to Ready]

[Tokyo 2024-03-23; Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4958.

  1. Modify 25.5.7.2 [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) — If C does not satisfy input_range or convertible_to<range_reference_t<R>, range_value_t<C>> is true:

      1. […]

    2. (2.2) — Otherwise, if input_range<range_reference_t<R>> is true:

      to<C>(ref_view(r) | views::transform([](auto&& elem) {
        return to<range_value_t<C>>(std::forward<decltype(elem)>(elem));
      }), std::forward<Args>(args)...);
      
    3. (2.3) — Otherwise, the program is ill-formed.