mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-24 11:35:31 +08:00
libstdc++: Optimize std::tuple_element and std::tuple_size_v
This reduces the number of class template instantiations needed for code using tuples, by reusing _Nth_type in tuple_element and specializing tuple_size_v for tuple, pair and array (and const-qualified versions of them). Also define the _Nth_type primary template as a complete type (but with no nested 'type' member). This avoids "invalid use of incomplete type" errors for out-of-range specializations of tuple_element. Those errors would probably be confusing and unhelpful for users. We already have a user-friendly static assert in tuple_element itself. Also ensure that tuple_size_v is available whenever tuple_size is (as proposed by LWG 3387). We already do that for tuple_element_t. libstdc++-v3/ChangeLog: * include/bits/stl_pair.h (tuple_size_v): Define partial specializations for std::pair. * include/bits/utility.h (_Nth_type): Move definition here and define primary template. (tuple_size_v): Move definition here. * include/std/array (tuple_size_v): Define partial specializations for std::array. * include/std/tuple (tuple_size_v): Move primary template to <bits/utility.h>. Define partial specializations for std::tuple. (tuple_element): Change definition to use _Nth_type. * include/std/variant (_Nth_type): Move to <bits/utility.h>. (variant_alternative, variant): Adjust qualification of _Nth_type. * testsuite/20_util/tuple/element_access/get_neg.cc: Prune additional errors from _Nth_type.
This commit is contained in:
parent
1b4a63593b
commit
09aab7e699
@ -771,6 +771,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
struct tuple_element<1, pair<_Tp1, _Tp2>>
|
struct tuple_element<1, pair<_Tp1, _Tp2>>
|
||||||
{ typedef _Tp2 type; };
|
{ typedef _Tp2 type; };
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
template<typename _Tp1, typename _Tp2>
|
||||||
|
inline constexpr size_t tuple_size_v<pair<_Tp1, _Tp2>> = 2;
|
||||||
|
|
||||||
|
template<typename _Tp1, typename _Tp2>
|
||||||
|
inline constexpr size_t tuple_size_v<const pair<_Tp1, _Tp2>> = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// @cond undocumented
|
/// @cond undocumented
|
||||||
template<size_t _Int>
|
template<size_t _Int>
|
||||||
struct __pair_get;
|
struct __pair_get;
|
||||||
|
@ -70,6 +70,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
|
struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
|
||||||
: public tuple_size<_Tp> { };
|
: public tuple_size<_Tp> { };
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
template<typename _Tp>
|
||||||
|
inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Gives the type of the ith element of a given tuple type.
|
/// Gives the type of the ith element of a given tuple type.
|
||||||
template<size_t __i, typename _Tp>
|
template<size_t __i, typename _Tp>
|
||||||
struct tuple_element;
|
struct tuple_element;
|
||||||
@ -97,8 +102,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
};
|
};
|
||||||
|
|
||||||
#if __cplusplus >= 201402L
|
#if __cplusplus >= 201402L
|
||||||
// The standard says this macro and alias template should be in <tuple>
|
// The standard says this macro and alias template should be in <tuple> but we
|
||||||
// but we define them here, to be available in <utility> and <array> too.
|
// we define them here, to be available in <array>, <utility> and <ranges> too.
|
||||||
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
|
// 3378. tuple_size_v/tuple_element_t should be available when
|
||||||
|
// tuple_size/tuple_element are
|
||||||
#define __cpp_lib_tuple_element_t 201402L
|
#define __cpp_lib_tuple_element_t 201402L
|
||||||
|
|
||||||
template<size_t __i, typename _Tp>
|
template<size_t __i, typename _Tp>
|
||||||
@ -195,6 +203,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
#endif // C++17
|
#endif // C++17
|
||||||
#endif // C++14
|
#endif // C++14
|
||||||
|
|
||||||
|
template<size_t _Np, typename... _Types>
|
||||||
|
struct _Nth_type
|
||||||
|
{ };
|
||||||
|
|
||||||
|
template<typename _Tp0, typename... _Rest>
|
||||||
|
struct _Nth_type<0, _Tp0, _Rest...>
|
||||||
|
{ using type = _Tp0; };
|
||||||
|
|
||||||
|
template<typename _Tp0, typename _Tp1, typename... _Rest>
|
||||||
|
struct _Nth_type<1, _Tp0, _Tp1, _Rest...>
|
||||||
|
{ using type = _Tp1; };
|
||||||
|
|
||||||
|
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
||||||
|
struct _Nth_type<2, _Tp0, _Tp1, _Tp2, _Rest...>
|
||||||
|
{ using type = _Tp2; };
|
||||||
|
|
||||||
|
template<size_t _Np, typename _Tp0, typename _Tp1, typename _Tp2,
|
||||||
|
typename... _Rest>
|
||||||
|
#if __cpp_concepts
|
||||||
|
requires (_Np >= 3)
|
||||||
|
#endif
|
||||||
|
struct _Nth_type<_Np, _Tp0, _Tp1, _Tp2, _Rest...>
|
||||||
|
: _Nth_type<_Np - 3, _Rest...>
|
||||||
|
{ };
|
||||||
|
|
||||||
|
#if ! __cpp_concepts // Need additional specializations to avoid ambiguities.
|
||||||
|
template<typename _Tp0, typename _Tp1, typename... _Rest>
|
||||||
|
struct _Nth_type<0, _Tp0, _Tp1, _Rest...>
|
||||||
|
{ using type = _Tp0; };
|
||||||
|
|
||||||
|
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
||||||
|
struct _Nth_type<0, _Tp0, _Tp1, _Tp2, _Rest...>
|
||||||
|
{ using type = _Tp0; };
|
||||||
|
|
||||||
|
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
||||||
|
struct _Nth_type<1, _Tp0, _Tp1, _Tp2, _Rest...>
|
||||||
|
{ using type = _Tp1; };
|
||||||
|
#endif
|
||||||
|
|
||||||
_GLIBCXX_END_NAMESPACE_VERSION
|
_GLIBCXX_END_NAMESPACE_VERSION
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -481,6 +481,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
using type = _Tp;
|
using type = _Tp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
template<typename _Tp, size_t _Nm>
|
||||||
|
inline constexpr size_t tuple_size_v<array<_Tp, _Nm>> = _Nm;
|
||||||
|
|
||||||
|
template<typename _Tp, size_t _Nm>
|
||||||
|
inline constexpr size_t tuple_size_v<const array<_Tp, _Nm>> = _Nm;
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename _Tp, size_t _Nm>
|
template<typename _Tp, size_t _Nm>
|
||||||
struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
|
struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
|
||||||
{ };
|
{ };
|
||||||
|
@ -1344,36 +1344,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||||||
struct tuple_size<tuple<_Elements...>>
|
struct tuple_size<tuple<_Elements...>>
|
||||||
: public integral_constant<size_t, sizeof...(_Elements)> { };
|
: public integral_constant<size_t, sizeof...(_Elements)> { };
|
||||||
|
|
||||||
#if __cplusplus > 201402L
|
#if __cplusplus >= 201703L
|
||||||
template <typename _Tp>
|
template<typename... _Types>
|
||||||
inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value;
|
inline constexpr size_t tuple_size_v<tuple<_Types>>
|
||||||
|
= sizeof...(_Types);
|
||||||
|
|
||||||
|
template<typename... _Types>
|
||||||
|
inline constexpr size_t tuple_size_v<const tuple<_Types>>
|
||||||
|
= sizeof...(_Types);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/// Trait to get the Ith element type from a tuple.
|
||||||
* Recursive case for tuple_element: strip off the first element in
|
template<size_t __i, typename... _Types>
|
||||||
* the tuple and retrieve the (i-1)th element of the remaining tuple.
|
struct tuple_element<__i, tuple<_Types...>>
|
||||||
*/
|
|
||||||
template<size_t __i, typename _Head, typename... _Tail>
|
|
||||||
struct tuple_element<__i, tuple<_Head, _Tail...> >
|
|
||||||
: tuple_element<__i - 1, tuple<_Tail...> > { };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basis case for tuple_element: The first element is the one we're seeking.
|
|
||||||
*/
|
|
||||||
template<typename _Head, typename... _Tail>
|
|
||||||
struct tuple_element<0, tuple<_Head, _Tail...> >
|
|
||||||
{
|
{
|
||||||
typedef _Head type;
|
static_assert(__i < sizeof...(_Types), "tuple index must be in range");
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
using type = typename _Nth_type<__i, _Types...>::type;
|
||||||
* Error case for tuple_element: invalid index.
|
|
||||||
*/
|
|
||||||
template<size_t __i>
|
|
||||||
struct tuple_element<__i, tuple<>>
|
|
||||||
{
|
|
||||||
static_assert(__i < tuple_size<tuple<>>::value,
|
|
||||||
"tuple index must be in range");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t __i, typename _Head, typename... _Tail>
|
template<size_t __i, typename _Head, typename... _Tail>
|
||||||
|
@ -54,51 +54,6 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||||||
{
|
{
|
||||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
|
|
||||||
namespace __detail
|
|
||||||
{
|
|
||||||
namespace __variant
|
|
||||||
{
|
|
||||||
template<size_t _Np, typename... _Types>
|
|
||||||
struct _Nth_type;
|
|
||||||
|
|
||||||
template<typename _Tp0, typename... _Rest>
|
|
||||||
struct _Nth_type<0, _Tp0, _Rest...>
|
|
||||||
{ using type = _Tp0; };
|
|
||||||
|
|
||||||
template<typename _Tp0, typename _Tp1, typename... _Rest>
|
|
||||||
struct _Nth_type<1, _Tp0, _Tp1, _Rest...>
|
|
||||||
{ using type = _Tp1; };
|
|
||||||
|
|
||||||
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
|
||||||
struct _Nth_type<2, _Tp0, _Tp1, _Tp2, _Rest...>
|
|
||||||
{ using type = _Tp2; };
|
|
||||||
|
|
||||||
template<size_t _Np, typename _Tp0, typename _Tp1, typename _Tp2,
|
|
||||||
typename... _Rest>
|
|
||||||
#if __cpp_concepts
|
|
||||||
requires (_Np >= 3)
|
|
||||||
#endif
|
|
||||||
struct _Nth_type<_Np, _Tp0, _Tp1, _Tp2, _Rest...>
|
|
||||||
: _Nth_type<_Np - 3, _Rest...>
|
|
||||||
{ };
|
|
||||||
|
|
||||||
#if ! __cpp_concepts // Need additional specializations to avoid ambiguities.
|
|
||||||
template<typename _Tp0, typename _Tp1, typename... _Rest>
|
|
||||||
struct _Nth_type<0, _Tp0, _Tp1, _Rest...>
|
|
||||||
{ using type = _Tp0; };
|
|
||||||
|
|
||||||
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
|
||||||
struct _Nth_type<0, _Tp0, _Tp1, _Tp2, _Rest...>
|
|
||||||
{ using type = _Tp0; };
|
|
||||||
|
|
||||||
template<typename _Tp0, typename _Tp1, typename _Tp2, typename... _Rest>
|
|
||||||
struct _Nth_type<1, _Tp0, _Tp1, _Tp2, _Rest...>
|
|
||||||
{ using type = _Tp1; };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace __variant
|
|
||||||
} // namespace __detail
|
|
||||||
|
|
||||||
#if __cplusplus >= 202002L && __cpp_concepts
|
#if __cplusplus >= 202002L && __cpp_concepts
|
||||||
// P2231R1 constexpr needs constexpr unions and constrained destructors.
|
// P2231R1 constexpr needs constexpr unions and constrained destructors.
|
||||||
# define __cpp_lib_variant 202106L
|
# define __cpp_lib_variant 202106L
|
||||||
@ -145,8 +100,7 @@ namespace __variant
|
|||||||
{
|
{
|
||||||
static_assert(_Np < sizeof...(_Types));
|
static_assert(_Np < sizeof...(_Types));
|
||||||
|
|
||||||
using type
|
using type = typename _Nth_type<_Np, _Types...>::type;
|
||||||
= typename __detail::__variant::_Nth_type<_Np, _Types...>::type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t _Np, typename _Variant>
|
template<size_t _Np, typename _Variant>
|
||||||
@ -1442,8 +1396,7 @@ namespace __variant
|
|||||||
= __detail::__variant::__accepted_index<_Tp, variant>::value;
|
= __detail::__variant::__accepted_index<_Tp, variant>::value;
|
||||||
|
|
||||||
template<size_t _Np, typename = enable_if_t<(_Np < sizeof...(_Types))>>
|
template<size_t _Np, typename = enable_if_t<(_Np < sizeof...(_Types))>>
|
||||||
using __to_type
|
using __to_type = typename _Nth_type<_Np, _Types...>::type;
|
||||||
= typename __detail::__variant::_Nth_type<_Np, _Types...>::type;
|
|
||||||
|
|
||||||
template<typename _Tp, typename = enable_if_t<__not_self<_Tp>>>
|
template<typename _Tp, typename = enable_if_t<__not_self<_Tp>>>
|
||||||
using __accepted_type = __to_type<__accepted_index<_Tp>>;
|
using __accepted_type = __to_type<__accepted_index<_Tp>>;
|
||||||
@ -1580,7 +1533,7 @@ namespace __variant
|
|||||||
emplace(_Args&&... __args)
|
emplace(_Args&&... __args)
|
||||||
{
|
{
|
||||||
namespace __variant = std::__detail::__variant;
|
namespace __variant = std::__detail::__variant;
|
||||||
using type = typename __variant::_Nth_type<_Np, _Types...>::type;
|
using type = typename _Nth_type<_Np, _Types...>::type;
|
||||||
// Provide the strong exception-safety guarantee when possible,
|
// Provide the strong exception-safety guarantee when possible,
|
||||||
// to avoid becoming valueless.
|
// to avoid becoming valueless.
|
||||||
if constexpr (is_nothrow_constructible_v<type, _Args...>)
|
if constexpr (is_nothrow_constructible_v<type, _Args...>)
|
||||||
@ -1620,7 +1573,7 @@ namespace __variant
|
|||||||
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
emplace(initializer_list<_Up> __il, _Args&&... __args)
|
||||||
{
|
{
|
||||||
namespace __variant = std::__detail::__variant;
|
namespace __variant = std::__detail::__variant;
|
||||||
using type = typename __variant::_Nth_type<_Np, _Types...>::type;
|
using type = typename _Nth_type<_Np, _Types...>::type;
|
||||||
// Provide the strong exception-safety guarantee when possible,
|
// Provide the strong exception-safety guarantee when possible,
|
||||||
// to avoid becoming valueless.
|
// to avoid becoming valueless.
|
||||||
if constexpr (is_nothrow_constructible_v<type,
|
if constexpr (is_nothrow_constructible_v<type,
|
||||||
@ -1803,8 +1756,7 @@ namespace __variant
|
|||||||
constexpr size_t __max = 11; // "These go to eleven."
|
constexpr size_t __max = 11; // "These go to eleven."
|
||||||
|
|
||||||
// The type of the first variant in the pack.
|
// The type of the first variant in the pack.
|
||||||
using _V0
|
using _V0 = typename _Nth_type<0, _Variants...>::type;
|
||||||
= typename __detail::__variant::_Nth_type<0, _Variants...>::type;
|
|
||||||
// The number of alternatives in that first variant.
|
// The number of alternatives in that first variant.
|
||||||
constexpr auto __n = variant_size_v<remove_reference_t<_V0>>;
|
constexpr auto __n = variant_size_v<remove_reference_t<_V0>>;
|
||||||
|
|
||||||
|
@ -60,3 +60,4 @@ test03()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// { dg-error "tuple index must be in range" "" { target *-*-* } 0 }
|
// { dg-error "tuple index must be in range" "" { target *-*-* } 0 }
|
||||||
|
// { dg-prune-output "no type named 'type' in .*_Nth_type" }
|
||||||
|
Loading…
Reference in New Issue
Block a user