Created on 2023-11-08.00:00:00 last changed 9 months ago
Proposed resolution:
This wording is relative to N4964.
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:
(2.1) — If C does not satisfy input_range or convertible_to<range_reference_t<R>, range_value_t<C>> is true:
[…]
(2.2) — Otherwise, if same_as<range_reference_t<R>, range_value_t<C>> is false and input_range<range_reference_t<R>> is true:
to<C>(r | views::transform([](auto&& elem) { return to<range_value_t<C>>(std::forward<decltype(elem)>(elem)); }), std::forward<Args>(args)...);(2.3) — Otherwise, the program is ill-formed.
[ 2024-03-11; Reflector poll ]
Set priority to 3 after reflector poll.
"Do we want same_as
or !different-from
?"
[range.utility.conv.to]/2 says:
(2.1) — If C does not satisfy input_range or convertible_to<range_reference_t<R>, range_value_t<C>> is true:
[…]
(2.2) — Otherwise, if input_range<range_reference_t<R>> is true:
to<C>(r | views::transform([](auto&& elem) { return to<range_value_t<C>>(std::forward<decltype(elem)>(elem)); }), std::forward<Args>(args)...);[…]
That is, if range_reference_t<R> is not convertible to range_value_t<C>, and range_reference_t<R> is an input range, views::transform is applied to convert the inner range to range_value_t<C> (through to<range_value_t<C>>), and then the transformed range is converted to C (through to<C>).
Consider:#include <ranges> struct ImmovableRange { ImmovableRange(int*, int*); ImmovableRange(ImmovableRange&&) = delete; int* begin(); int* end(); }; struct C { ImmovableRange* begin(); ImmovableRange* end(); }; using R = int[1][2]; void test() { (void)std::ranges::to<C>(R{}); }
Here:
convertible_to<range_reference_t<R>, range_value_t<C>> is false.
range_reference_t<R> satisfies input_range.
range_reference_t<R> can be converted to range_value_t<C> through to<range_value_t<C>>. (If it couldn't, an error would be produced immediately.)
So to<C> is called recursively, constructing C with the transformed range (whose range_reference_t<R> is the same as range_value_t<C>). For the construction from the transformed range:
range_reference_t<R> and range_value_t<C> are both ImmovableRange.
convertible_to<range_reference_t<R>, range_value_t<C>> (i.e. convertible_to<ImmovableRange, ImmovableRange>) is false.
range_reference_t<R> (i.e. ImmovableRange) satisfies input_range.
range_reference_t<R> can be converted to range_value_t<C> through to<range_value_t<C>>.
So to<C> is called recursively again, transforming the range for the second time. This time, the transformation does not change any of the above four facts. As a result, to<C> is called yet again, leading to an infinite recursion.
I believe this can be fixed by stop calling to<C> recursively when range_reference_t<R> is the same as range_value_t<C>.History | |||
---|---|---|---|
Date | User | Action | Args |
2024-03-11 21:55:38 | admin | set | messages: + msg13982 |
2023-11-18 10:32:08 | admin | set | messages: + msg13857 |
2023-11-08 00:00:00 | admin | create |