mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
libstdc++: Implement structured binding support for integer_sequence
This implements P1789R3 Library Support for Expansion Statements. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf libstdc++-v3/ChangeLog: * include/bits/utility.h (std::tuple_size, std::tuple_element): Add partial specializations for integer_sequence. (std::get(integer_sequence<_Tp, _Idx...>)): Define. * include/bits/version.def (integer_sequence): Bump to 202511L. * 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. * testsuite/experimental/feat-cxx14.cc: Updated check for __cpp_lib_integer_sequence value. Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Co-authored-by: Ivan Lazaric <ivan.lazaric1@gmail.com> Signed-off-by: Matthias Wippich <mfwippich@gmail.com>
This commit is contained in:
committed by
Tomasz Kamiński
parent
88b1c71f0b
commit
6159bfcf8b
@@ -481,6 +481,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
static constexpr size_t size() noexcept { return sizeof...(_Idx); }
|
||||
};
|
||||
|
||||
#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
|
||||
/** @brief Structured binding support for `integer_sequence`
|
||||
|
||||
* @since 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>
|
||||
[[nodiscard]]
|
||||
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
|
||||
|
||||
@@ -184,6 +184,11 @@ ftms = {
|
||||
|
||||
ftms = {
|
||||
name = integer_sequence;
|
||||
values = {
|
||||
v = 202511;
|
||||
cxxmin = 26;
|
||||
extra_cond = "__cpp_pack_indexing";
|
||||
};
|
||||
values = {
|
||||
v = 201304;
|
||||
cxxmin = 14;
|
||||
|
||||
@@ -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
|
||||
|
||||
143
libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
Normal file
143
libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
Normal file
@@ -0,0 +1,143 @@
|
||||
// { 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 );
|
||||
}
|
||||
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
/* Unimplemented, see PR117784
|
||||
{
|
||||
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 );
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
auto idx = 0;
|
||||
static constexpr auto seq = std::make_index_sequence<4>{};
|
||||
template for (constexpr auto elem : seq)
|
||||
{
|
||||
VERIFY( elem == idx );
|
||||
++idx;
|
||||
}
|
||||
VERIFY( idx == 4 );
|
||||
}
|
||||
|
||||
|
||||
/* Unimplemented, see PR117784
|
||||
{
|
||||
auto idx = 0;
|
||||
constexpr auto seq = std::make_index_sequence<4>{};
|
||||
template for (constexpr auto elem : seq)
|
||||
{
|
||||
VERIFY( elem == idx );
|
||||
++idx;
|
||||
}
|
||||
VERIFY( idx == 4 );
|
||||
}
|
||||
|
||||
{
|
||||
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() );
|
||||
@@ -0,0 +1,22 @@
|
||||
// { 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" }
|
||||
}
|
||||
|
||||
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
|
||||
// { dg-error "cannot index an empty pack" "" { target *-*-* } 0 }
|
||||
// { dg-error "pack index '.' is out of range for pack of length" "" { target *-*-* } 0 }
|
||||
@@ -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
|
||||
|
||||
#ifndef __cpp_lib_exchange_function
|
||||
|
||||
Reference in New Issue
Block a user