C++ Logo

std-proposals

Advanced search

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

From: Paolo Di Giglio <p.digiglio91_at_[hidden]>
Date: Tue, 1 Mar 2022 18:36:05 +0100
Thanks everybody for your precious feedback.

Let me recap what I think I understood and what I surely didn't
understand:

 1. A specialization of function template std::get for r-value to array
 is still required, and should return a r-value reference to the i-th
 element in the array.

 2. @Nikolay, I can't understand how would the following implementation
 prevent me from accessing an out-of-bound index, which was the initial
 feature wanted to accomplish:

> template<std::size_t IX, typename T>
> auto const &get(T const *a){
> return a[IX];
> }

 3. @Arthur and @DBJ, about the requires vs static_assert implementation,
 I'd stick to the same implementation as std::array. A quick look at the
 MSVC implementation shows they're using static_assert. However, I don't
 know if this is mandated by the standard.

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];
}

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.

Now, about the tuple interface. Thanks @Zhihao for pointing me to you
earlier work and @Giuseppe for making me aware of P2165. In proposing
the above std::get specialization, I was actually only trying to let the
compiler retain as much information as possible about the array to
perform out-of-bound checks. 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.

However, at least in my mind, std::array<T,N> is the C++ version of
T[N]. So my initial proposal of a new std::get specialization was also
motivated by the lack symmetry in the standard. By pushing this symmetry
reasoning further, maybe T[N] should implement the tuple interface,
since std::array<T,N> does. Is there any drawback in doing so?

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;

I'm not sure if this would introduce breaking changes. Most probably,
the following specializations for std::array would be breaking changes:

 * std::is_array (true);
 * std::is_unbounded_array (false);
 * std::is_bounded_array (true).


Il giorno mar 1 mar 2022 alle ore 18:21 Nikolay Mihaylov via Std-Proposals <
std-proposals_at_[hidden]> ha scritto:

> Sure and since is template parameter, it will still checked for non
> constexpr version. E.g. kind of.
>
> However I still think we can have something similar to pointers too.
>
> One more minor point defending pointer version - unless optimized away,
> this will generate loooots of functions. I love templates, but it will
> bloat the code.
>
> Nick.
>
> On Tuesday, March 1, 2022, DBJ via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> That static_assert will kick in only if the function is called:
>>
>> #include <assert.h>
>> #include <cstdlib>
>>
>> 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];
>> }
>>
>> int main(void) {
>> constexpr int arr[99] = {1, 2, 3, 4};
>> static_assert(get<2>(arr) == 3);
>>
>> typedef decltype(&get<99>(arr)) wtf;
>> wtf p = &get<2>(arr); // works
>> }
>>
>> C++20 requires variant is better.
>>
>> DBJ
>>
>> On Tue, 1 Mar 2022 at 17:39, Arthur O'Dwyer via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> On Tue, Mar 1, 2022 at 11:34 AM Barry Revzin <barry.revzin_at_[hidden]>
>>> wrote:
>>>
>>>> On Tue, Mar 1, 2022 at 9:59 AM Arthur O'Dwyer via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>> On Tue, Mar 1, 2022 at 10:13 AM Nikolay Mihaylov via Std-Proposals <
>>>>> std-proposals_at_[hidden]> wrote:
>>>>>
>>>>>> Once again, why do we need the size?
>>>>>> Shall we check the size?
>>>>>> Via static_assert?
>>>>>> During runtime?
>>>>>>
>>>>>
>>>>> In the proposed std::get for C arrays, AIUI, the size would be part of
>>>>> the signature. It would look like this:
>>>>>
>>>>> template<size_t X, class T, size_t N> requires (X < N)
>>>>> constexpr T& get(T (&arr)[N]) noexcept {
>>>>> return arr[X];
>>>>> }
>>>>>
>>>>
>>>> No, it wouldn't. Paulo's email contained the correct implementation:
>>>>
>>>> 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];
>>>> }
>>>>
>>>> This would match what std::get does for std::array, std::pair, and
>>>> std::tuple.
>>>>
>>>
>>> Oh, gross. If it's not going to be SFINAE-friendly, then I don't
>>> particularly have an opinion what it does.
>>>
>>> –Arthur
>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>
>> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2022-03-01 17:33:25