ranges::to
reserve
s the wrong sizeSection: 25.5.7.2 [range.utility.conv.to] Status: New Submitter: Hewill Kang Opened: 2022-06-20 Last modified: 2024-01-29
Priority: 4
View other active issues in [range.utility.conv.to].
View all other issues in [range.utility.conv.to].
View all issues with New status.
Discussion:
In bullet 1.1.4 of ranges::to
, if the Container
satisfies container-insertable
and R
models sized_range
, it will first construct the Container
with args...
and then preallocate memory by calling c.reserve()
.
However, this only makes sense when c
is default-initialized. If instead the size of the Container
created by args...
is not 0
, the value passed into c.reserve()
will be wrong, for example:
ranges::to<std::string>(std::views::single('o'), "hell");
The size of the string
created by "hell"
is already 4
, whereas the size of
R
is only 1
, which makes c.reserve(1)
useless.
[2022-07-08; Reflector poll]
Set priority to 4 after reflector poll. Some suggestions for NAD.
Proposed resolution:
This wording is relative to N4910.
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- Returns: An object of type
C
constructed from the elements ofr
in the following manner:
(1.1) — If
convertible_to<range_reference_t<R>, range_value_t<C>>
istrue
:
(1.1.1) — If
constructible_from<C, R, Args...>
istrue
:C(std::forward<R>(r), std::forward<Args>(args)...)
(1.1.2) — Otherwise, if
constructible_from<C, from_range_t, R, Args...>
istrue
:C(from_range, std::forward<R>(r), std::forward<Args>(args)...)
(1.1.3) — Otherwise, if
(1.1.3.1) —
common_range<R>
istrue
,(1.1.3.2) —
cpp17-input-iterator<iterator_t<R>>
istrue
, and(1.1.3.3) —
constructible_from<C, iterator_t<R>, sentinel_t<R>, Args...>
istrue
:C(ranges::begin(r), ranges::end(r), std::forward<Args>(args)...)
(1.1.4) — Otherwise, if
(1.1.4.1) —
constructible_from<C, Args...>
istrue
, and(1.1.4.2) —
container-insertable<C, range_reference_t<R>>
istrue
:C c(std::forward<Args>(args)...); if constexpr (sized_range<R> && reservable-container<C>) { using ST = range_size_t<C>; using CT = common_type_t<ST, range_size_t<R>>; auto sz = ST(CT(ranges::size(c)) + CT(ranges::size(r))); c.reserve(szranges::size(r)); } ranges::copy(r, container-inserter<range_reference_t<R>>(c));(1.2) — Otherwise, if
input_range<range_reference_t<R>>
istrue
:to<C>(r | views::transform([](auto&& elem) { return to<range_value_t<C>>(std::forward<decltype(elem)>(elem)); }), std::forward<Args>(args)...);(1.3) — Otherwise, the program is ill-formed.