C++23 introduced the very powerful ranges::to
for constructing an object (usually a container) from a range, with the following definition ([range.utility.conv.to]):
template<class C, input_range R, class... Args> requires (!view<C>)
constexpr C to(R&& r, Args&&... args);
Note that it only constrains the template parameter C
not to be a view
, that is, C
may not even be a range
.
However, its implementation uses range_value_t<C>
to obtain the element type of C
, which makes C
at least a range
given the range_value_t
constraint that the template parameter R
must model a range
.
So, why is ranges::to
so loosely constrained on the template parameter C
?
I noticed that the R3 version of the paper used to constrain C
to be input_range
, which was apparently reasonable since input_range
guaranteed that the range_value_t
to be well-formed, but in R4 this constraint was removed. And I didn't find any comments about this change.
So, what are the considerations for removing the constraint that C
must be input_range
?
Is there a practical example of the benefits of this constraint relaxation?
requires(input_range<C>)
= "shall not participate in overload resolution if not input_range, SFINAE/concepts friendly", but being ill-formed if not range allows astatic_assert
, like in this implementation. Unsure how this interacts with yourrange_value_t<C>
point. – En