[PATCH v2] libstdc++: Implement structured binding support for integer_sequence

Tomasz Kaminski tkaminsk@redhat.com
Thu Apr 9 07:52:27 GMT 2026


On Thu, Apr 9, 2026 at 4:45 AM Matthias Wippich <mfwippich@gmail.com> wrote:

> This implements P1789R3 Library Support for Expansion Statements.
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>
> Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
> Feature-test macro integer_sequence has been bumped to 202511L.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/utility.h:
>         Implement structured bindings protocol for std::integer_sequence.
>
This should list entities added.

>         * include/bits/version.def: Bump integer_sequence feature-test
> macro.
>         * include/bits/version.h: Regenerate.
>         * testsuite/20_util/integer_sequence/tuple_access.cc: New test.
>         * testsuite/20_util/integer_sequence/tuple_access_neg.cc: New test.
>
> Co-authored-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> Signed-off-by: Matthias Wippich <mfwippich@gmail.com>
> ---
>
There is another test that needs updating, and few whitespace errors.
--- a/libstdc++-v3/testsuite/experimental/feat-cxx14.cc
+++ b/libstdc++-v3/testsuite/experimental/feat-cxx14.cc
@@ -18,8 +18,8 @@

 #ifndef  __cpp_lib_integer_sequence
 #  error "__cpp_lib_integer_sequence"
-#elif  __cpp_lib_integer_sequence != 201304
-#  error "__cpp_lib_integer_sequence != 201304"
+#elif  __cpp_lib_integer_sequence < 201304
+#  error "__cpp_lib_integer_sequence < 201304"
 #endif

I am doing above changes locally and will post new revision.


>  libstdc++-v3/include/bits/utility.h           | 30 ++++++
>  libstdc++-v3/include/bits/version.def         |  5 +
>  libstdc++-v3/include/bits/version.h           |  7 +-
>  .../20_util/integer_sequence/tuple_access.cc  | 96 +++++++++++++++++++
>  .../integer_sequence/tuple_access_neg.cc      | 21 ++++
>  5 files changed, 158 insertions(+), 1 deletion(-)
>  create mode 100644
> libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
>  create mode 100644
> libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
>
> diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h
> index 93e9e9f9dba..363aed478c5 100644
> --- a/libstdc++-v3/include/bits/utility.h
> +++ b/libstdc++-v3/include/bits/utility.h
> @@ -481,6 +481,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        static constexpr size_t size() noexcept { return sizeof...(_Idx); }
>      };
>
> +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
> +
> +  /// Structured binding support
> +  template<typename _Tp, _Tp... _Idx>
> +    struct tuple_size<integer_sequence<_Tp, _Idx...>>
> +    : integral_constant<size_t, sizeof...(_Idx)> { };
> +
> +  template<size_t __i, class _Tp, _Tp... _Idx>
> +    struct tuple_element<__i, integer_sequence<_Tp, _Idx...>>
> +    {
> +      static_assert(__i < sizeof...(_Idx));
> +      using type = _Tp;
> +    };
> +
> +  template<size_t __i, class _Tp, _Tp... _Idx>
> +    struct tuple_element<__i, const integer_sequence<_Tp, _Idx...>>
> +    {
> +      static_assert(__i < sizeof...(_Idx));
> +      using type = _Tp;
> +    };
> +
> +  template<size_t __i, class _Tp, _Tp... _Idx>
> +    constexpr _Tp
> +    get (integer_sequence<_Tp, _Idx...>) noexcept
> +    {
> +      static_assert(__i < sizeof...(_Idx));
> +      return _Idx...[__i];
> +    }
> +#endif // __glibcxx_integer_sequence >= 202511L
> +
>    /// Alias template make_integer_sequence
>    template<typename _Tp, _Tp _Num>
>      using make_integer_sequence
> diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> index cfb90533ce4..8db3c1d2df3 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -184,6 +184,11 @@ ftms = {
>
>  ftms = {
>    name = integer_sequence;
> +  values = {
> +    v = 202511;
> +    cxxmin = 26;
> +    extra_cond = "__cpp_pack_indexing";
> +  };
>    values = {
>      v = 201304;
>      cxxmin = 14;
> diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> index 22dd31b9d32..455d7190e90 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -186,7 +186,12 @@
>  #undef __glibcxx_want_exchange_function
>
>  #if !defined(__cpp_lib_integer_sequence)
> -# if (__cplusplus >= 201402L)
> +# if (__cplusplus >  202302L) && (__cpp_pack_indexing)
> +#  define __glibcxx_integer_sequence 202511L
> +#  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_integer_sequence)
> +#   define __cpp_lib_integer_sequence 202511L
> +#  endif
> +# elif (__cplusplus >= 201402L)
>  #  define __glibcxx_integer_sequence 201304L
>  #  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_integer_sequence)
>  #   define __cpp_lib_integer_sequence 201304L
> diff --git
> a/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
> b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
> new file mode 100644
> index 00000000000..a942d1d8396
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
> @@ -0,0 +1,96 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <utility>
> +#include <tuple>
> +#include <testsuite_hooks.h>
> +
> +#if __cpp_lib_integer_sequence < 202511L
> +# error "Feature-test macro __cpp_lib_integer_sequence is incorrect"
> +#endif
> +
> +constexpr auto
> +destructure_sum(auto seq)
> +{
> +  auto [...elems] = seq;
> +  return (0 + ... + elems);
> +}
> +
> +using IS1 = std::make_index_sequence<10>;
> +static_assert( std::tuple_size_v<IS1> == 10 );
> +static_assert( std::is_same_v<std::tuple_element_t<3, IS1>, std::size_t>
> );
> +static_assert( std::get<7>(IS1{}) == 7 );
> +static_assert( destructure_sum(IS1{}) == 45 );
> +static_assert( noexcept(get<0>(IS1{})) );
> +
> +using IS2 = std::integer_sequence<int, 42, 101, -13>;
> +static_assert( std::tuple_size_v<IS2> == 3 );
> +static_assert( std::is_same_v<std::tuple_element_t<1, IS2>, int> );
> +static_assert( std::get<2>(IS2{}) == -13 );
> +static_assert( destructure_sum(IS2{}) == 130 );
> +static_assert( noexcept(get<0>(IS2{})) );
> +
> +using IS3 = std::integer_sequence<char>;
> +static_assert( std::tuple_size_v<IS3> == 0 );
> +
> +using IS4 = std::integer_sequence<int, 1, 2>;
> +static_assert( !std::is_constructible_v<std::pair<int, int>, IS4> );
> +static_assert( !std::is_constructible_v<std::tuple<int, int>, IS4> );
> +
> +template<typename = void>
> +constexpr bool
> +test_basic()
> +{
> +  {
> +    auto [...elems] = std::make_index_sequence<0>{};
> +    static_assert( sizeof...(elems) == 0 );
> +  }
> +
> +  {
> +    auto [...elems] = std::integer_sequence<int, 3, 5, 7, 11>{};
> +
> +    static_assert( sizeof...(elems) == 4 );
> +
> +    VERIFY( elems...[0] == 3 );
> +    VERIFY( elems...[1] == 5 );
> +    VERIFY( elems...[2] == 7 );
> +    VERIFY( elems...[3] == 11 );
> +  }
> +
> +  {
> +    static constexpr auto [...elems] = std::integer_sequence<short, 2, 4,
> 8, 16>{};
> +
> +    static_assert( sizeof...(elems) == 4 );
> +
> +    static_assert( elems...[0] == 2 );
> +    static_assert( elems...[1] == 4 );
> +    static_assert( elems...[2] == 8 );
> +    static_assert( elems...[3] == 16 );
> +  }
> +
> +  {
> +    constexpr auto [...elems] = std::integer_sequence<int, 1, 8, 2, 11>{};
> +
> +    static_assert( sizeof...(elems) == 4 );
> +
> +    static_assert( elems...[0] == 1 );
> +    static_assert( elems...[1] == 8 );
> +    static_assert( elems...[2] == 2 );
> +    static_assert( elems...[3] == 11 );
> +  }
> +
> +  /* Unimplemented, see
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117784
> +  {
> +    auto idx = 0;
> +    template for (constexpr auto elem : std::make_index_sequence<4>{})
> +      {
> +       VERIFY( elem == idx );
> +       ++idx;
> +      }
> +    VERIFY( idx == 4 );
> +  }
> +  */
> +
> +  return true;
> +}
> +
> +static_assert( test_basic() );
> diff --git
> a/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
> b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
> new file mode 100644
> index 00000000000..42c57620e91
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
> @@ -0,0 +1,21 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <utility>
> +
> +using empty = std::integer_sequence<int>;
> +static_assert( std::is_same_v<std::tuple_element_t<0, empty>, int> ); //
> { dg-error "here" }
> +static_assert( std::is_same_v<std::tuple_element_t<0, const empty>, int>
> ); // { dg-error "here" }
> +
> +using size4 = std::integer_sequence<int, 1, 9, 7, 15>;
> +static_assert( std::is_same_v<std::tuple_element_t<4, size4>, int> ); //
> { dg-error "here" }
> +static_assert( std::is_same_v<std::tuple_element_t<4, const size4>, int>
> ); // { dg-error "here" }
> +
> +void
> +test()
> +{
> +  (void)std::get<0>(empty{}); // { dg-error "here" }
> +  (void)std::get<4>(size4{}); // { dg-error "here" }
>
There are trailing whitespace at the end of the lines above and test()
file, removed them.

> +}
> +
> +// { dg-error "static assertion failed" "" { target *-*-* } 0 }
> +// { dg-excess-errors "" }
> --
> 2.53.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260409/3fa58f8e/attachment.htm>


More information about the Libstdc++ mailing list