See attached test.cpp. I prefer the VIA_ARRAY=1 solution (generalized to 
arbitrary integer types).

g++ -std=c++26 -O2 -Wall -c test.cpp -ftime-report:

- GGC Total of 74M for -DVIA_ARRAY=0

- GGC Total of 67M for -DVIA_ARRAY=1

hyperfine says:

Benchmark 1: ~/.local/gcc-16/bin/g++ -std=c++26 -O2 -Wall -c test.cpp 
-DVIA_ARRAY=0                                                                   
                                                                                
                                                                                
                              
  Time (mean ± σ):   683.7 ms ±  86.2 ms  [User: 621.3 ms, System: 58.9 ms]     
                                                                                
                                                                                
                                                                                
                
  Range (min … max): 509.6 ms … 779.7 ms  10 runs                               
                                                                                
                                                                                
                                                                                
                
                                                                                
                                                                                
                                                                                
                                                                                
                    
Benchmark 2: ~/.local/gcc-16/bin/g++ -std=c++26 -O2 -Wall -c test.cpp 
-DVIA_ARRAY=1                                                                   
                                                                                
                                                                                
                              
  Time (mean ± σ):   418.0 ms ± 172.2 ms  [User: 376.9 ms, System: 39.2 ms]     
                                                                                
                                                                                
                                                                                
                
  Range (min … max): 264.2 ms … 703.2 ms  10 runs                               
                                                                                
                                                                                
                                                                                
                
                                                                                
                                                                                
                                                                                
                                                                                
                    
Summary                                                                         
                                                                                
                                                                                
                                                                                
                    
  ~/.local/gcc-16/bin/g++ -std=c++26 -O2 -Wall -c test.cpp -DVIA_ARRAY=1 ran    
                                                                                
                                                                                
                                                                                
                    
    1.64 ± 0.70 times faster than ~/.local/gcc-16/bin/g++ -std=c++26 -O2 -Wall 
-c test.cpp -DVIA_ARRAY=0

- Matthias

Tomasz Kamiński [Monday, 13 October 2025, 14:40:33 CEST]:
> This patch introduces the internal helper type _IndexPack to support
> introducing a pack of indices via a structured binding declaration:
> static constexpr auto [...__is] = _IndexPack<N>();
> 
> _IndexPack is a distinct type from _Index_tuple and index_sequence to
> enable a simpler implementation: it requires only a single template
> parameter, and get<I> performs returns I. Implementing get as a
> static member avoids making it visible for ADL overload resolution.
> 
> The use of static on the structured binding is required to work around
> PR122269 [1].
> 
> [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122269
> 
> libstdc++-v3/ChangeLog:
> 
>       * include/bits/utility.h (_IndexPack, tuple_size<_IndexPack<_Num>>)
>       (tuple_element<_Idx, _IndexPack<_Num>>): Define.
>       * testsuite/ext/indexpack.cc: New test.
> ---
> Tested on x86_64-linux locally. OK for trunk?
> 
>  libstdc++-v3/include/bits/utility.h     | 19 +++++++++++++++++++
>  libstdc++-v3/testsuite/ext/indexpack.cc | 19 +++++++++++++++++++
>  2 files changed, 38 insertions(+)
>  create mode 100644 libstdc++-v3/testsuite/ext/indexpack.cc
> 
> diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h index 4e574658eba..2bc8629cb92 100644
> --- a/libstdc++-v3/include/bits/utility.h
> +++ b/libstdc++-v3/include/bits/utility.h
> @@ -313,6 +313,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      inline constexpr bool __is_nontype_v<nontype_t<__val>> = true;
>  #endif
> 
> +#if __cpp_structured_bindings >= 202411L
> +  template<size_t _Num>
> +  struct _IndexPack
> +  {
> +    template<size_t _Idx>
> +      static consteval size_t
> +      get() noexcept
> +      { return _Idx; }
> +  };
> +
> +  template<size_t _Num>
> +    struct tuple_size<_IndexPack<_Num>>
> +    { static constexpr size_t value = _Num; };
> +
> +  template<size_t _Idx, size_t _Num>
> +    struct tuple_element<_Idx, _IndexPack<_Num>>
> +    { using type = size_t; };
> +#endif
> +
>  _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace
> 
> diff --git a/libstdc++-v3/testsuite/ext/indexpack.cc
> b/libstdc++-v3/testsuite/ext/indexpack.cc new file mode 100644
> index 00000000000..929d77e6bf1
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/ext/indexpack.cc
> @@ -0,0 +1,19 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <utility>
> +
> +template<std::size_t N>
> +void test()
> +{
> +  // PR122269 static should not be necessary
> +  static constexpr auto [...ids] = std::_IndexPack<N>();
> +  static_assert( sizeof...(ids) == N );
> +  static_assert( (ids + ... + 0) == N*(N-1)/2 );
> +}
> +
> +int main()
> +{
> +  test<0>();
> +  test<4>();
> +  test<8>();
> +}


-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Center for Heavy Ion Research               https://gsi.de
 std::simd
──────────────────────────────────────────────────────────────────────────
#include <bits/utility.h>
#include <span>

namespace std
{
#if VIA_ARRAY

template <size_t N>
  inline constexpr size_t
  index_pack[N] = {__integer_pack(size_t(N))...};

#else

template<size_t _Num>
  struct index_pack
  {
    template<size_t _Idx>
      static consteval const size_t&
      get() noexcept
      {
        static constexpr size_t val = _Idx;
        return val;
      }
  };

template<size_t _Num>
  struct tuple_size<index_pack<_Num>>
  { static constexpr size_t value = _Num; };

template<size_t _Idx, size_t _Num>
  struct tuple_element<_Idx, index_pack<_Num>>
  { using type = size_t; };

#endif
}

template <std::size_t N>
  unsigned f(std::span<const int, N> data)
  {
    constexpr auto [...is] = std::index_pack<N>
#if VIA_ARRAY
                             ;
#else
                               ();
#endif
    return (data[is] + ...);
  }

unsigned g(std::span<const int> data)
{
  return f(data.subspan<0, 1>())
           + f(data.subspan<0, 2>())
           + f(data.subspan<0, 3>())
           + f(data.subspan<0, 4>())
           + f(data.subspan<0, 5>())
           + f(data.subspan<0, 6>())
           + f(data.subspan<0, 7>())
           + f(data.subspan<0, 8>())
           + f(data.subspan<0, 9>())
           + f(data.subspan<0, 10>())
           + f(data.subspan<0, 11>())
           + f(data.subspan<0, 12>())
           + f(data.subspan<0, 13>())
           + f(data.subspan<0, 14>())
           + f(data.subspan<0, 15>())
           + f(data.subspan<0, 16>())
           + f(data.subspan<0, 17>())
           + f(data.subspan<0, 18>())
           + f(data.subspan<0, 19>())
           + f(data.subspan<0, 20>())
           + f(data.subspan<0, 21>())
           + f(data.subspan<0, 22>())
           + f(data.subspan<0, 23>())
           + f(data.subspan<0, 24>())
           + f(data.subspan<0, 25>())
           + f(data.subspan<0, 26>())
           + f(data.subspan<0, 27>())
           + f(data.subspan<0, 28>())
           + f(data.subspan<0, 29>());
}

Reply via email to