libstdc++: Reduce header dependencies on <array> and <utility>

This refactoring reduces the memory usage and compilation time to parse
a number of headers that depend on std::pair, std::tuple or std::array.
Previously the headers for these class templates were all intertwined,
due to the common dependency on std::tuple_size, std::tuple_element and
their std::get overloads. This decouples the headers by moving some
parts of <utility> into a new <bits/utility.h> header. This means that
<array> and <tuple> no longer need to include the whole of <utility>,
and <tuple> no longer needs to include <array>.

This decoupling benefits headers such as <thread> and <scoped_allocator>
which only need std::tuple, and so no longer have to parse std::array.

Some other headers such as <any>, <optional> and <variant> no longer
need to include <utility> just for the std::in_place tag types, so
do not have to parse the std::pair definitions.

Removing direct uses of <utility> also means that the std::rel_ops
namespace is not transitively declared by other headers.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/Makefile.am: Add bits/utility.h header.
	* include/Makefile.in: Regenerate.
	* include/bits/utility.h: New file.
	* include/std/utility (tuple_size, tuple_element): Move
	to new header.
	* include/std/type_traits (__is_tuple_like_impl<tuple<T...>>):
	Move to <tuple>.
	(_Index_tuple, _Build_index_tuple, integer_sequence): Likewise.
	(in_place_t, in_place_index_t, in_place_type_t): Likewise.
	* include/bits/ranges_util.h: Include new header instead of
	<utility>.
	* include/bits/stl_pair.h (tuple_size, tuple_element): Move
	partial specializations for std::pair here.
	(get): Move overloads for std::pair here.
	* include/std/any: Include new header instead of <utility>.
	* include/std/array: Likewise.
	* include/std/memory_resource: Likewise.
	* include/std/optional: Likewise.
	* include/std/variant: Likewise.
	* include/std/tuple: Likewise.
	(__is_tuple_like_impl<tuple<T...>>): Move here.
	(get) Declare overloads for std::array.
	* include/std/version (__cpp_lib_tuples_by_type): Change type
	to long.
	* testsuite/20_util/optional/84601.cc: Include <utility>.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc:
	Likewise.
	* testsuite/23_containers/array/tuple_interface/get_neg.cc:
	Adjust dg-error line numbers.
	* testsuite/std/ranges/access/cbegin.cc: Include <utility>.
	* testsuite/std/ranges/access/cend.cc: Likewise.
	* testsuite/std/ranges/access/end.cc: Likewise.
	* testsuite/std/ranges/single_view.cc: Likewise.
This commit is contained in:
Jonathan Wakely 2021-07-22 14:48:27 +01:00
parent fcc7c6369f
commit 261d5a4a45
21 changed files with 433 additions and 344 deletions

View File

@ -233,6 +233,7 @@ bits_headers = \
${bits_srcdir}/unordered_set.h \
${bits_srcdir}/uses_allocator.h \
${bits_srcdir}/uses_allocator_args.h \
${bits_srcdir}/utility.h \
${bits_srcdir}/valarray_array.h \
${bits_srcdir}/valarray_array.tcc \
${bits_srcdir}/valarray_before.h \

View File

@ -583,6 +583,7 @@ bits_headers = \
${bits_srcdir}/unordered_set.h \
${bits_srcdir}/uses_allocator.h \
${bits_srcdir}/uses_allocator_args.h \
${bits_srcdir}/utility.h \
${bits_srcdir}/valarray_array.h \
${bits_srcdir}/valarray_array.tcc \
${bits_srcdir}/valarray_before.h \

View File

@ -32,6 +32,7 @@
#if __cplusplus > 201703L
# include <bits/ranges_base.h>
# include <bits/utility.h>
#ifdef __cpp_lib_ranges
namespace std _GLIBCXX_VISIBILITY(default)

View File

@ -56,12 +56,12 @@
#ifndef _STL_PAIR_H
#define _STL_PAIR_H 1
#include <bits/move.h> // for std::move / std::forward, and std::swap
#if __cplusplus >= 201103L
# include <type_traits> // for std::__decay_and_strip, std::is_reference_v
# include <type_traits> // for std::__decay_and_strip
# include <bits/move.h> // for std::move / std::forward, and std::swap
# include <bits/utility.h> // for std::tuple_element, std::tuple_size
#endif
#if __cplusplus > 201703L
#if __cplusplus >= 202002L
# include <compare>
# define __cpp_lib_constexpr_utility 201811L
#endif
@ -752,6 +752,153 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// @}
#if __cplusplus >= 201103L
// Various functions which give std::pair a tuple-like interface.
template<typename _T1, typename _T2>
struct __is_tuple_like_impl<pair<_T1, _T2>> : true_type
{ };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_size<pair<_Tp1, _Tp2>>
: public integral_constant<size_t, 2> { };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_element<0, pair<_Tp1, _Tp2>>
{ typedef _Tp1 type; };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_element<1, pair<_Tp1, _Tp2>>
{ typedef _Tp2 type; };
/// @cond undocumented
template<size_t _Int>
struct __pair_get;
template<>
struct __pair_get<0>
{
template<typename _Tp1, typename _Tp2>
static constexpr _Tp1&
__get(pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.first; }
template<typename _Tp1, typename _Tp2>
static constexpr _Tp1&&
__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<_Tp1>(__pair.first); }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp1&
__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.first; }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp1&&
__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<const _Tp1>(__pair.first); }
};
template<>
struct __pair_get<1>
{
template<typename _Tp1, typename _Tp2>
static constexpr _Tp2&
__get(pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.second; }
template<typename _Tp1, typename _Tp2>
static constexpr _Tp2&&
__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<_Tp2>(__pair.second); }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp2&
__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.second; }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp2&&
__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<const _Tp2>(__pair.second); }
};
/// @endcond
/** @{
* std::get overloads for accessing members of std::pair
*/
template<size_t _Int, class _Tp1, class _Tp2>
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
get(pair<_Tp1, _Tp2>& __in) noexcept
{ return __pair_get<_Int>::__get(__in); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
get(pair<_Tp1, _Tp2>&& __in) noexcept
{ return __pair_get<_Int>::__move_get(std::move(__in)); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
get(const pair<_Tp1, _Tp2>& __in) noexcept
{ return __pair_get<_Int>::__const_get(__in); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
get(const pair<_Tp1, _Tp2>&& __in) noexcept
{ return __pair_get<_Int>::__const_move_get(std::move(__in)); }
#if __cplusplus >= 201402L
#define __cpp_lib_tuples_by_type 201304L
template <typename _Tp, typename _Up>
constexpr _Tp&
get(pair<_Tp, _Up>& __p) noexcept
{ return __p.first; }
template <typename _Tp, typename _Up>
constexpr const _Tp&
get(const pair<_Tp, _Up>& __p) noexcept
{ return __p.first; }
template <typename _Tp, typename _Up>
constexpr _Tp&&
get(pair<_Tp, _Up>&& __p) noexcept
{ return std::move(__p.first); }
template <typename _Tp, typename _Up>
constexpr const _Tp&&
get(const pair<_Tp, _Up>&& __p) noexcept
{ return std::move(__p.first); }
template <typename _Tp, typename _Up>
constexpr _Tp&
get(pair<_Up, _Tp>& __p) noexcept
{ return __p.second; }
template <typename _Tp, typename _Up>
constexpr const _Tp&
get(const pair<_Up, _Tp>& __p) noexcept
{ return __p.second; }
template <typename _Tp, typename _Up>
constexpr _Tp&&
get(pair<_Up, _Tp>&& __p) noexcept
{ return std::move(__p.second); }
template <typename _Tp, typename _Up>
constexpr const _Tp&&
get(const pair<_Up, _Tp>&& __p) noexcept
{ return std::move(__p.second); }
#endif // C++14
/// @}
#endif // C++11
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

View File

@ -0,0 +1,205 @@
// Utilities used throughout the library -*- C++ -*-
// Copyright (C) 2004-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file include/bits/utility.h
* This is an internal header file, included by other library headers.
* Do not attempt to use it directly. @headername{utility}
*
* This file contains the parts of `<utility>` needed by other headers,
* so they don't need to include the whole of `<utility>`.
*/
#ifndef _GLIBCXX_UTILITY_H
#define _GLIBCXX_UTILITY_H 1
#pragma GCC system_header
#if __cplusplus >= 201103L
#include <type_traits>
#include <bits/move.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Finds the size of a given tuple type.
template<typename _Tp>
struct tuple_size;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2313. tuple_size should always derive from integral_constant<size_t, N>
// 2770. tuple_size<const T> specialization is not SFINAE compatible
template<typename _Tp,
typename _Up = typename remove_cv<_Tp>::type,
typename = typename enable_if<is_same<_Tp, _Up>::value>::type,
size_t = tuple_size<_Tp>::value>
using __enable_if_has_tuple_size = _Tp;
template<typename _Tp>
struct tuple_size<const __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
template<typename _Tp>
struct tuple_size<volatile __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
template<typename _Tp>
struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
/// Gives the type of the ith element of a given tuple type.
template<size_t __i, typename _Tp>
struct tuple_element;
// Duplicate of C++14's tuple_element_t for internal use in C++11 mode
template<size_t __i, typename _Tp>
using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
template<size_t __i, typename _Tp>
struct tuple_element<__i, const _Tp>
{
typedef typename add_const<__tuple_element_t<__i, _Tp>>::type type;
};
template<size_t __i, typename _Tp>
struct tuple_element<__i, volatile _Tp>
{
typedef typename add_volatile<__tuple_element_t<__i, _Tp>>::type type;
};
template<size_t __i, typename _Tp>
struct tuple_element<__i, const volatile _Tp>
{
typedef typename add_cv<__tuple_element_t<__i, _Tp>>::type type;
};
#if __cplusplus >= 201402L
// The standard says this macro and alias template should be in <tuple>
// but we define them here, to be available in <utility> and <array> too.
#define __cpp_lib_tuple_element_t 201402L
template<size_t __i, typename _Tp>
using tuple_element_t = typename tuple_element<__i, _Tp>::type;
#endif // C++14
// Stores a tuple of indices. Used by tuple and pair, and by bind() to
// extract the elements in a tuple.
template<size_t... _Indexes> struct _Index_tuple { };
// Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
template<size_t _Num>
struct _Build_index_tuple
{
#if __has_builtin(__make_integer_seq)
template<typename, size_t... _Indices>
using _IdxTuple = _Index_tuple<_Indices...>;
// Clang defines __make_integer_seq for this purpose.
using __type = __make_integer_seq<_IdxTuple, size_t, _Num>;
#else
// For GCC and other compilers, use __integer_pack instead.
using __type = _Index_tuple<__integer_pack(_Num)...>;
#endif
};
#if __cplusplus >= 201402L
#define __cpp_lib_integer_sequence 201304L
/// Class template integer_sequence
template<typename _Tp, _Tp... _Idx>
struct integer_sequence
{
typedef _Tp value_type;
static constexpr size_t size() noexcept { return sizeof...(_Idx); }
};
/// Alias template make_integer_sequence
template<typename _Tp, _Tp _Num>
using make_integer_sequence
#if __has_builtin(__make_integer_seq)
= __make_integer_seq<integer_sequence, _Tp, _Num>;
#else
= integer_sequence<_Tp, __integer_pack(_Num)...>;
#endif
/// Alias template index_sequence
template<size_t... _Idx>
using index_sequence = integer_sequence<size_t, _Idx...>;
/// Alias template make_index_sequence
template<size_t _Num>
using make_index_sequence = make_integer_sequence<size_t, _Num>;
/// Alias template index_sequence_for
template<typename... _Types>
using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
#if __cplusplus >= 201703L
//
struct in_place_t {
explicit in_place_t() = default;
};
inline constexpr in_place_t in_place{};
template<typename _Tp> struct in_place_type_t
{
explicit in_place_type_t() = default;
};
template<typename _Tp>
inline constexpr in_place_type_t<_Tp> in_place_type{};
template<size_t _Idx> struct in_place_index_t
{
explicit in_place_index_t() = default;
};
template<size_t _Idx>
inline constexpr in_place_index_t<_Idx> in_place_index{};
template<typename>
struct __is_in_place_type_impl : false_type
{ };
template<typename _Tp>
struct __is_in_place_type_impl<in_place_type_t<_Tp>> : true_type
{ };
template<typename _Tp>
struct __is_in_place_type
: public __is_in_place_type_impl<_Tp>
{ };
#endif // C++17
#endif // C++14
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif // C++11
#endif /* _GLIBCXX_UTILITY_H */

View File

@ -33,10 +33,11 @@
#if __cplusplus >= 201703L
#include <initializer_list>
#include <typeinfo>
#include <new>
#include <utility>
#include <type_traits>
#include <bits/utility.h> // in_place_type_t
namespace std _GLIBCXX_VISIBILITY(default)
{

View File

@ -35,10 +35,14 @@
# include <bits/c++0x_warning.h>
#else
#include <utility>
#include <compare>
#include <initializer_list>
#include <type_traits>
#include <bits/functexcept.h>
#include <bits/stl_algobase.h>
#include <bits/range_access.h>
#include <bits/range_access.h> // std::begin, std::end etc.
#include <bits/utility.h> // std::index_sequence, std::tuple_size
#include <debug/assertions.h>
namespace std _GLIBCXX_VISIBILITY(default)
@ -428,28 +432,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Tuple interface to class template array.
/// tuple_size
template<typename _Tp>
struct tuple_size;
/// Partial specialization for std::array
template<typename _Tp, std::size_t _Nm>
template<typename _Tp, size_t _Nm>
struct tuple_size<array<_Tp, _Nm>>
: public integral_constant<std::size_t, _Nm> { };
/// tuple_element
template<std::size_t _Int, typename _Tp>
struct tuple_element;
: public integral_constant<size_t, _Nm> { };
/// Partial specialization for std::array
template<std::size_t _Int, typename _Tp, std::size_t _Nm>
struct tuple_element<_Int, array<_Tp, _Nm>>
template<size_t _Ind, typename _Tp, size_t _Nm>
struct tuple_element<_Ind, array<_Tp, _Nm>>
{
static_assert(_Int < _Nm, "index is out of bounds");
typedef _Tp type;
static_assert(_Ind < _Nm, "array index is in range");
using type = _Tp;
};
template<typename _Tp, std::size_t _Nm>
template<typename _Tp, size_t _Nm>
struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
{ };

View File

@ -38,13 +38,13 @@
#include <shared_mutex> // shared_mutex
#include <bits/align.h> // align
#include <bits/functexcept.h> // __throw_bad_array_new_length
#include <bits/uses_allocator.h> // __use_alloc
#include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc
#include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
#include <ext/numeric_traits.h>
#include <debug/assertions.h>
#if ! __cpp_lib_make_obj_using_allocator
# include <utility> // pair, index_sequence
# include <bits/utility.h> // index_sequence
# include <tuple> // tuple, forward_as_tuple
#endif
@ -338,10 +338,10 @@ namespace pmr
{ return _M_resource; }
private:
#if ! __cpp_lib_make_obj_using_allocator
using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
#if ! __cpp_lib_make_obj_using_allocator
template<typename _Ind, typename... _Args>
static tuple<_Args&&...>
_S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)

View File

@ -33,14 +33,14 @@
#if __cplusplus >= 201703L
#include <utility>
#include <type_traits>
#include <exception>
#include <new>
#include <initializer_list>
#include <bits/enable_special_members.h>
#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
#include <bits/enable_special_members.h>
#include <bits/utility.h> // in_place_t
#if __cplusplus > 201703L
# include <compare>
#endif

View File

@ -35,10 +35,10 @@
# include <bits/c++0x_warning.h>
#else
#include <utility>
#include <array>
#include <bits/uses_allocator.h>
#include <bits/invoke.h>
#include <bits/stl_pair.h> // for std::pair
#include <bits/uses_allocator.h> // for std::allocator_arg_t
#include <bits/utility.h> // for std::get, std::tuple_size etc.
#include <bits/invoke.h> // for std::__invoke
#if __cplusplus > 201703L
# include <compare>
# define __cpp_lib_constexpr_tuple 201811L
@ -1415,7 +1415,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201402L
#define __cpp_lib_tuples_by_type 201304
#define __cpp_lib_tuples_by_type 201304L
// Return the index of _Tp in _Types, if it occurs exactly once.
// Otherwise, return sizeof...(_Types).
@ -1613,6 +1613,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
forward_as_tuple(_Elements&&... __args) noexcept
{ return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
// Declarations of std::array and its std::get overloads, so that
// std::tuple_cat can use them if <tuple> is included before <array>.
template<typename _Tp, size_t _Nm> struct array;
template<size_t _Int, typename _Tp, size_t _Nm>
constexpr _Tp&
get(array<_Tp, _Nm>&) noexcept;
template<size_t _Int, typename _Tp, size_t _Nm>
constexpr _Tp&&
get(array<_Tp, _Nm>&&) noexcept;
template<size_t _Int, typename _Tp, size_t _Nm>
constexpr const _Tp&
get(const array<_Tp, _Nm>&) noexcept;
template<size_t _Int, typename _Tp, size_t _Nm>
constexpr const _Tp&&
get(const array<_Tp, _Nm>&&) noexcept;
template<size_t, typename, typename, size_t>
struct __make_tuple_impl;
@ -1721,6 +1743,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
template<typename... _Tps>
struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
{ };
/// tuple_cat
template<typename... _Tpls, typename = typename
enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type>

View File

@ -41,9 +41,6 @@ namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Elements>
class tuple;
template<typename _Tp>
class reference_wrapper;
@ -2680,10 +2677,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __is_tuple_like_impl : false_type
{ };
template<typename... _Tps>
struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
{ };
// Internal type trait that allows us to sfinae-protect tuple_cat.
template<typename _Tp>
struct __is_tuple_like

View File

@ -60,9 +60,8 @@
/**
* @defgroup utilities Utilities
*
* Components deemed generally useful. Includes pair, tuple,
* forward/move helpers, ratio, function object, metaprogramming and
* type traits, time, date, and memory functions.
* Basic function and class templates used with the rest of the library.
* Includes pair, swap, forward/move helpers, declval, integer_sequence.
*/
#include <bits/c++config.h>
@ -71,218 +70,21 @@
#if __cplusplus >= 201103L
#include <initializer_list>
#include <type_traits>
#include <bits/move.h>
#include <initializer_list>
#include <bits/utility.h>
#if __cplusplus > 201703L
#include <ext/numeric_traits.h>
#if __cplusplus >= 202002L
#include <ext/numeric_traits.h> // __is_standard_integer, __int_traits
#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Finds the size of a given tuple type.
template<typename _Tp>
struct tuple_size;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2313. tuple_size should always derive from integral_constant<size_t, N>
// 2770. tuple_size<const T> specialization is not SFINAE compatible
template<typename _Tp,
typename _Up = typename remove_cv<_Tp>::type,
typename = typename enable_if<is_same<_Tp, _Up>::value>::type,
size_t = tuple_size<_Tp>::value>
using __enable_if_has_tuple_size = _Tp;
template<typename _Tp>
struct tuple_size<const __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
template<typename _Tp>
struct tuple_size<volatile __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
template<typename _Tp>
struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
: public tuple_size<_Tp> { };
/// Gives the type of the ith element of a given tuple type.
template<size_t __i, typename _Tp>
struct tuple_element;
// Duplicate of C++14's tuple_element_t for internal use in C++11 mode
template<size_t __i, typename _Tp>
using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
template<size_t __i, typename _Tp>
struct tuple_element<__i, const _Tp>
{
typedef typename add_const<__tuple_element_t<__i, _Tp>>::type type;
};
template<size_t __i, typename _Tp>
struct tuple_element<__i, volatile _Tp>
{
typedef typename add_volatile<__tuple_element_t<__i, _Tp>>::type type;
};
template<size_t __i, typename _Tp>
struct tuple_element<__i, const volatile _Tp>
{
typedef typename add_cv<__tuple_element_t<__i, _Tp>>::type type;
};
#if __cplusplus >= 201402L
// The standard says this macro and alias template should be in <tuple>
// but we define them here, to be available when the partial specializations
// of tuple_element<pair<T,U>> and tuple_element<array<T,N>> are defined.
#define __cpp_lib_tuple_element_t 201402L
template<size_t __i, typename _Tp>
using tuple_element_t = typename tuple_element<__i, _Tp>::type;
#endif
// Various functions which give std::pair a tuple-like interface.
/// Partial specialization for std::pair
template<typename _T1, typename _T2>
struct __is_tuple_like_impl<pair<_T1, _T2>> : true_type
{ };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_size<pair<_Tp1, _Tp2>>
: public integral_constant<size_t, 2> { };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_element<0, pair<_Tp1, _Tp2>>
{ typedef _Tp1 type; };
/// Partial specialization for std::pair
template<class _Tp1, class _Tp2>
struct tuple_element<1, pair<_Tp1, _Tp2>>
{ typedef _Tp2 type; };
template<size_t _Int>
struct __pair_get;
template<>
struct __pair_get<0>
{
template<typename _Tp1, typename _Tp2>
static constexpr _Tp1&
__get(pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.first; }
template<typename _Tp1, typename _Tp2>
static constexpr _Tp1&&
__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<_Tp1>(__pair.first); }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp1&
__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.first; }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp1&&
__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<const _Tp1>(__pair.first); }
};
template<>
struct __pair_get<1>
{
template<typename _Tp1, typename _Tp2>
static constexpr _Tp2&
__get(pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.second; }
template<typename _Tp1, typename _Tp2>
static constexpr _Tp2&&
__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<_Tp2>(__pair.second); }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp2&
__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
{ return __pair.second; }
template<typename _Tp1, typename _Tp2>
static constexpr const _Tp2&&
__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
{ return std::forward<const _Tp2>(__pair.second); }
};
template<size_t _Int, class _Tp1, class _Tp2>
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
get(pair<_Tp1, _Tp2>& __in) noexcept
{ return __pair_get<_Int>::__get(__in); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
get(pair<_Tp1, _Tp2>&& __in) noexcept
{ return __pair_get<_Int>::__move_get(std::move(__in)); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
get(const pair<_Tp1, _Tp2>& __in) noexcept
{ return __pair_get<_Int>::__const_get(__in); }
template<size_t _Int, class _Tp1, class _Tp2>
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
get(const pair<_Tp1, _Tp2>&& __in) noexcept
{ return __pair_get<_Int>::__const_move_get(std::move(__in)); }
#if __cplusplus >= 201402L
#define __cpp_lib_tuples_by_type 201304
template <typename _Tp, typename _Up>
constexpr _Tp&
get(pair<_Tp, _Up>& __p) noexcept
{ return __p.first; }
template <typename _Tp, typename _Up>
constexpr const _Tp&
get(const pair<_Tp, _Up>& __p) noexcept
{ return __p.first; }
template <typename _Tp, typename _Up>
constexpr _Tp&&
get(pair<_Tp, _Up>&& __p) noexcept
{ return std::move(__p.first); }
template <typename _Tp, typename _Up>
constexpr const _Tp&&
get(const pair<_Tp, _Up>&& __p) noexcept
{ return std::move(__p.first); }
template <typename _Tp, typename _Up>
constexpr _Tp&
get(pair<_Up, _Tp>& __p) noexcept
{ return __p.second; }
template <typename _Tp, typename _Up>
constexpr const _Tp&
get(const pair<_Up, _Tp>& __p) noexcept
{ return __p.second; }
template <typename _Tp, typename _Up>
constexpr _Tp&&
get(pair<_Up, _Tp>&& __p) noexcept
{ return std::move(__p.second); }
template <typename _Tp, typename _Up>
constexpr const _Tp&&
get(const pair<_Up, _Tp>&& __p) noexcept
{ return std::move(__p.second); }
#define __cpp_lib_exchange_function 201304
#define __cpp_lib_exchange_function 201304L
/// Assign @p __new_val to @p __obj and return its previous value.
template <typename _Tp, typename _Up = _Tp>
@ -291,100 +93,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
exchange(_Tp& __obj, _Up&& __new_val)
{ return std::__exchange(__obj, std::forward<_Up>(__new_val)); }
#endif // C++14
#if __cplusplus >= 201703L
// Stores a tuple of indices. Used by tuple and pair, and by bind() to
// extract the elements in a tuple.
template<size_t... _Indexes> struct _Index_tuple { };
// Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
template<size_t _Num>
struct _Build_index_tuple
{
#if __has_builtin(__make_integer_seq)
template<typename, size_t... _Indices>
using _IdxTuple = _Index_tuple<_Indices...>;
// Clang defines __make_integer_seq for this purpose.
using __type = __make_integer_seq<_IdxTuple, size_t, _Num>;
#else
// For GCC and other compilers, use __integer_pack instead.
using __type = _Index_tuple<__integer_pack(_Num)...>;
#endif
};
#if __cplusplus >= 201402L
#define __cpp_lib_integer_sequence 201304
/// Class template integer_sequence
template<typename _Tp, _Tp... _Idx>
struct integer_sequence
{
typedef _Tp value_type;
static constexpr size_t size() noexcept { return sizeof...(_Idx); }
};
/// Alias template make_integer_sequence
template<typename _Tp, _Tp _Num>
using make_integer_sequence
#if __has_builtin(__make_integer_seq)
= __make_integer_seq<integer_sequence, _Tp, _Num>;
#else
= integer_sequence<_Tp, __integer_pack(_Num)...>;
#endif
/// Alias template index_sequence
template<size_t... _Idx>
using index_sequence = integer_sequence<size_t, _Idx...>;
/// Alias template make_index_sequence
template<size_t _Num>
using make_index_sequence = make_integer_sequence<size_t, _Num>;
/// Alias template index_sequence_for
template<typename... _Types>
using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
#endif
#if __cplusplus > 201402L
struct in_place_t {
explicit in_place_t() = default;
};
inline constexpr in_place_t in_place{};
template<typename _Tp> struct in_place_type_t
{
explicit in_place_type_t() = default;
};
template<typename _Tp>
inline constexpr in_place_type_t<_Tp> in_place_type{};
template<size_t _Idx> struct in_place_index_t
{
explicit in_place_index_t() = default;
};
template<size_t _Idx>
inline constexpr in_place_index_t<_Idx> in_place_index{};
template<typename>
struct __is_in_place_type_impl : false_type
{ };
template<typename _Tp>
struct __is_in_place_type_impl<in_place_type_t<_Tp>> : true_type
{ };
template<typename _Tp>
struct __is_in_place_type
: public __is_in_place_type_impl<_Tp>
{ };
#define __cpp_lib_as_const 201510
#define __cpp_lib_as_const 201510L
template<typename _Tp>
[[nodiscard]]
constexpr add_const_t<_Tp>&
@ -476,6 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif // C++23
#endif // C++20
#endif // C++17
#endif // C++14
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

View File

@ -33,11 +33,10 @@
#if __cplusplus >= 201703L
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <bits/enable_special_members.h>
#include <bits/functexcept.h>
#include <bits/move.h>
#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
#include <bits/invoke.h>
#include <ext/aligned_buffer.h>
@ -45,6 +44,7 @@
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_construct.h>
#include <bits/utility.h> // in_place_index_t
#if __cplusplus > 201703L
# include <compare>
#endif

View File

@ -94,7 +94,7 @@
# define __cpp_lib_string_udls 201304
# define __cpp_lib_transparent_operators 201510
# define __cpp_lib_tuple_element_t 201402L
# define __cpp_lib_tuples_by_type 201304
# define __cpp_lib_tuples_by_type 201304L
#endif
#if __cplusplus >= 201703L

View File

@ -1,6 +1,7 @@
// { dg-do compile { target c++17 } }
#include <optional>
#include <utility>
using pair_t = std::pair<int, int>;
using opt_t = std::optional<pair_t>;

View File

@ -25,6 +25,7 @@
#include <span>
#include <string>
#include <vector>
#include <utility>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>

View File

@ -26,6 +26,6 @@ int n1 = std::get<1>(a);
int n2 = std::get<1>(std::move(a));
int n3 = std::get<1>(ca);
// { dg-error "static assertion failed" "" { target *-*-* } 363 }
// { dg-error "static assertion failed" "" { target *-*-* } 371 }
// { dg-error "static assertion failed" "" { target *-*-* } 379 }
// { dg-error "static assertion failed" "" { target *-*-* } 367 }
// { dg-error "static assertion failed" "" { target *-*-* } 375 }
// { dg-error "static assertion failed" "" { target *-*-* } 383 }

View File

@ -19,6 +19,7 @@
// { dg-do run { target c++2a } }
#include <ranges>
#include <utility> // as_const
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>

View File

@ -19,6 +19,7 @@
// { dg-do run { target c++2a } }
#include <ranges>
#include <utility> // as_const
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>

View File

@ -19,6 +19,7 @@
// { dg-do run { target c++2a } }
#include <ranges>
#include <utility> // as_const
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>

View File

@ -19,6 +19,7 @@
// { dg-do run { target c++2a } }
#include <ranges>
#include <utility> // as_const
#include <testsuite_hooks.h>
void