Date: Fri, 13 Dec 2024 17:20:58 -0500
On Fri, Dec 13, 2024 at 1:33 PM Hewill Kang via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Currently, the template parameter C of ranges::to<C>(r)
> <https://en.cppreference.com/w/cpp/ranges/to> cannot be a view, which
> means we cannot write the following:
>
> string s;
> auto sv = ranges::to<string_view>(s); // error, string_view is view
>
> I find this to be very inconvenient, as such limitation really prohibits a
> lot of useful use cases:
>
> string_view s = "1.2.3.4";
> auto r = s | views::split('.')
> | views::transform(ranges::to<std::string_view>()); //
> error
>
I'm not convinced that this is a proper use of `ranges::to`.
It *would* be a proper use of Avi Kivity's recently proposed
`std::construct`, <https://lists.isocpp.org/std-proposals/2024/12/11641.php>
which is explicitly designed to "lift" a constructor into a callable, and
for no other purpose, as in:
namespace std {
template<class T> struct construct {
static T operator()(auto&&... args) { return
T(decltype(args)(args)...); }
};
} // namespace std
auto r = s | views::split('.') |
views::transform(std::construct<std::string_view>());
Now, it's true that `ranges::to<T>` can already be used as a poor man's
version of `std::construct<T>`, but it suffers from two big limitations in
that respect:
(1) It won't just construct T from Args...; it will do a whole complicated
overload resolution and possibly end up constructing T from
`std::from_range_t, Args...` or some other bag of arguments entirely, which
is going to be error-prone and confusing, if what you really want is *just*
to lift the constructor into a callable. That is, `ranges::to` cannot be
used as a poor man's std::construct *in generic code*. (Still, it *can* be
used *as `ranges::to`* in generic code!)
(2) `ranges::to<T>` is constrained to work only when `T` is a non-view
range type, plus certain other constraints.
auto a = s | std::ranges::to<std::string>(); // OK
auto b = s | std::ranges::to<std::string_view>(); // ill-formed
SFINAE-friendly
auto c = s | std::ranges::to<std::filesystem::path>(); // ill-formed
hard-error
Your proposal asks to patch up a very tiny piece of (2), while leaving most
of (2) and all of (1) unfixed. That doesn't seem like a good idea to me.
Let `ranges::to` be `ranges::to`; if you want a way to lift a constructor
into a callable, don't misuse `ranges::to` for that purpose, but rather,
design a new thing that does *only* that lifting.
HTH,
–Arthur
std-proposals_at_[hidden]> wrote:
> Currently, the template parameter C of ranges::to<C>(r)
> <https://en.cppreference.com/w/cpp/ranges/to> cannot be a view, which
> means we cannot write the following:
>
> string s;
> auto sv = ranges::to<string_view>(s); // error, string_view is view
>
> I find this to be very inconvenient, as such limitation really prohibits a
> lot of useful use cases:
>
> string_view s = "1.2.3.4";
> auto r = s | views::split('.')
> | views::transform(ranges::to<std::string_view>()); //
> error
>
I'm not convinced that this is a proper use of `ranges::to`.
It *would* be a proper use of Avi Kivity's recently proposed
`std::construct`, <https://lists.isocpp.org/std-proposals/2024/12/11641.php>
which is explicitly designed to "lift" a constructor into a callable, and
for no other purpose, as in:
namespace std {
template<class T> struct construct {
static T operator()(auto&&... args) { return
T(decltype(args)(args)...); }
};
} // namespace std
auto r = s | views::split('.') |
views::transform(std::construct<std::string_view>());
Now, it's true that `ranges::to<T>` can already be used as a poor man's
version of `std::construct<T>`, but it suffers from two big limitations in
that respect:
(1) It won't just construct T from Args...; it will do a whole complicated
overload resolution and possibly end up constructing T from
`std::from_range_t, Args...` or some other bag of arguments entirely, which
is going to be error-prone and confusing, if what you really want is *just*
to lift the constructor into a callable. That is, `ranges::to` cannot be
used as a poor man's std::construct *in generic code*. (Still, it *can* be
used *as `ranges::to`* in generic code!)
(2) `ranges::to<T>` is constrained to work only when `T` is a non-view
range type, plus certain other constraints.
auto a = s | std::ranges::to<std::string>(); // OK
auto b = s | std::ranges::to<std::string_view>(); // ill-formed
SFINAE-friendly
auto c = s | std::ranges::to<std::filesystem::path>(); // ill-formed
hard-error
Your proposal asks to patch up a very tiny piece of (2), while leaving most
of (2) and all of (1) unfixed. That doesn't seem like a good idea to me.
Let `ranges::to` be `ranges::to`; if you want a way to lift a constructor
into a callable, don't misuse `ranges::to` for that purpose, but rather,
design a new thing that does *only* that lifting.
HTH,
–Arthur
Received on 2024-12-13 22:21:16