C++ Logo

std-proposals

Advanced search

Re: [std-proposals] C-style array specialization for std::get

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Tue, 1 Mar 2022 12:40:55 -0500
On Tue, Mar 1, 2022 at 12:33 PM Paolo Di Giglio via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
> So, at this stage, my proposed implementation of std::get would be the
> following:
>
> template <std::size_t Idx, typename T, std::size_t N>
> constexpr T& get(T (&arr)[N]) noexcept
> {
> static_assert(Idx < N, "Index out of bounds");
> return arr[Idx];
> }
>
> template <std::size_t Idx, typename T, std::size_t N>
> constexpr T&& get(T (&&arr)[N]) noexcept
> {
> static_assert(Idx < N, "Index out of bounds");
>
> using array_t = T(&&)[N];
> return std::forward<array_t>(arr)[Idx];
>

`T (&&arr)[N]` is not a forwarding reference, so you shouldn't use
std::forward here. Use std::move, because you intend to take this lvalue
and (unconditionally) turn it into an rvalue; that's what std::move is for.
See also https://quuxplusone.github.io/blog/2022/02/02/look-what-they-need/


> While four specializations are needed for std::array (i.e. const and
> non-const l- and r-value), I believe only two should suffice here as the
> compiler is able to deduce the const-ness of template parameter T.
>

Yep.


> [...] While I also thought about a specialization
> of std::tuple_size to query the array length, I rejected this idea since
> std::extent already does that. [...But] maybe T[N] should implement the
> tuple interface,
> since std::array<T,N> does. Is there any drawback in doing so?
>

Nope; if you're supporting `std::get` for C arrays, the only reason I can
imagine for doing so is because you want to support
    int arr[3] = {1,2,3};
    int [a,b,c] = arr;
and for that to work, you're going to *need* tuple_size and tuple_element.


Just as a speculation, I'd like to add the following. One step even
> further towards the std::array vs T[N] symmetry would be to specialize
> for std::array the following traits:
>
> * std::rank;
> * std::extent;
> * std::remove_extent;
> * std::remove_all_extents;
>

You can't do that. By design, std::array<T,N> is a class type, not an array
type. Similarly, we do not specialize
`std::is_pointer_v<std::unique_ptr<T>>` or even
`std::is_function_v<std::function<void()>>`.

Basically, think about the mantra "The C++ standard library is implemented
in C++." If it isn't already legal for a user-defined type `W` to
specialize `std::rank<W>`, then it generally shouldn't be made legal for a
library-defined type like `std::array<T,N>` or `std::vector<T>` to do so,
either.

–Arthur

Received on 2022-03-01 17:41:07