C++ Logo

std-proposals

Advanced search

Re: [std-proposals] ranges::to<view_type>?

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
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

Received on 2024-12-13 22:21:16