template<size_t...>
struct _Index_tuple;
+#if ! __cpp_lib_concepts
// Concept utility functions, reused in conditionally-explicit
// constructors.
// See PR 70437, don't look at is_constructible or
return false;
}
};
+#endif // lib concepts
#endif // C++11
template<typename _U1, typename _U2> class __pair_base
{
-#if __cplusplus >= 201103L
+#if __cplusplus >= 201103L && ! __cpp_lib_concepts
template<typename _T1, typename _T2> friend struct pair;
__pair_base() = default;
~__pair_base() = default;
*/
template<typename _T1, typename _T2>
struct pair
- : private __pair_base<_T1, _T2>
+ : public __pair_base<_T1, _T2>
{
typedef _T1 first_type; ///< The type of the `first` member
typedef _T2 second_type; ///< The type of the `second` member
_T2 second; ///< The second member
#if __cplusplus >= 201103L
- // C++11 (and later) implementation.
+ constexpr pair(const pair&) = default; ///< Copy constructor
+ constexpr pair(pair&&) = default; ///< Move constructor
+
+ template<typename... _Args1, typename... _Args2>
+ _GLIBCXX20_CONSTEXPR
+ pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
+
+ /// Swap the first members and then the second members.
+ _GLIBCXX20_CONSTEXPR void
+ swap(pair& __p)
+ noexcept(__and_<__is_nothrow_swappable<_T1>,
+ __is_nothrow_swappable<_T2>>::value)
+ {
+ using std::swap;
+ swap(first, __p.first);
+ swap(second, __p.second);
+ }
+
+ private:
+ template<typename... _Args1, size_t... _Indexes1,
+ typename... _Args2, size_t... _Indexes2>
+ _GLIBCXX20_CONSTEXPR
+ pair(tuple<_Args1...>&, tuple<_Args2...>&,
+ _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
+ public:
+
+#if __cpp_lib_concepts
+ // C++20 implementation using concepts, explicit(bool), fully constexpr.
+
+ /// Default constructor
+ constexpr
+ explicit(__not_<__and_<__is_implicitly_default_constructible<_T1>,
+ __is_implicitly_default_constructible<_T2>>>())
+ pair()
+ requires is_default_constructible_v<_T1>
+ && is_default_constructible_v<_T2>
+ : first(), second()
+ { }
+
+ private:
+
+ /// @cond undocumented
+ template<typename _U1, typename _U2>
+ static constexpr bool
+ _S_constructible()
+ {
+ if constexpr (is_constructible_v<_T1, _U1>)
+ return is_constructible_v<_T2, _U2>;
+ return false;
+ }
+
+ template<typename _U1, typename _U2>
+ static constexpr bool
+ _S_nothrow_constructible()
+ {
+ if constexpr (is_nothrow_constructible_v<_T1, _U1>)
+ return is_nothrow_constructible_v<_T2, _U2>;
+ return false;
+ }
+
+ template<typename _U1, typename _U2>
+ static constexpr bool
+ _S_convertible()
+ {
+ if constexpr (is_convertible_v<_U1, _T1>)
+ return is_convertible_v<_U2, _T2>;
+ return false;
+ }
+ /// @endcond
+
+ public:
+
+ /// Constructor accepting lvalues of `first_type` and `second_type`
+ constexpr explicit(!_S_convertible<const _T1&, const _T2&>())
+ pair(const _T1& __x, const _T2& __y)
+ noexcept(_S_nothrow_constructible<const _T1&, const _T2&>())
+ requires (_S_constructible<const _T1&, const _T2&>())
+ : first(__x), second(__y)
+ { }
+
+ /// Constructor accepting two values of arbitrary types
+ template<typename _U1, typename _U2>
+ requires (_S_constructible<_U1, _U2>())
+ constexpr explicit(!_S_convertible<_U1, _U2>())
+ pair(_U1&& __x, _U2&& __y)
+ noexcept(_S_nothrow_constructible<_U1, _U2>())
+ : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y))
+ { }
+
+ /// Converting constructor from a `pair<U1, U2>` lvalue
+ template<typename _U1, typename _U2>
+ requires (_S_constructible<const _U1&, const _U2&>())
+ constexpr explicit(!_S_convertible<const _U1&, const _U2&>())
+ pair(const pair<_U1, _U2>& __p)
+ noexcept(_S_nothrow_constructible<const _U1&, const _U2&>())
+ : first(__p.first), second(__p.second)
+ { }
+
+ /// Converting constructor from a `pair<U1, U2>` rvalue
+ template<typename _U1, typename _U2>
+ requires (_S_constructible<_U1, _U2>())
+ constexpr explicit(!_S_convertible<_U1, _U2>())
+ pair(pair<_U1, _U2>&& __p)
+ noexcept(_S_nothrow_constructible<_U1, _U2>())
+ : first(std::forward<_U1>(__p.first)),
+ second(std::forward<_U2>(__p.second))
+ { }
+
+ private:
+ /// @cond undocumented
+ template<typename _U1, typename _U2>
+ static constexpr bool
+ _S_assignable()
+ {
+ if constexpr (is_assignable_v<_T1&, _U1>)
+ return is_assignable_v<_T2&, _U2>;
+ return false;
+ }
+
+ template<typename _U1, typename _U2>
+ static constexpr bool
+ _S_nothrow_assignable()
+ {
+ if constexpr (is_nothrow_assignable_v<_T1&, _U1>)
+ return is_nothrow_assignable_v<_T2&, _U2>;
+ return false;
+ }
+ /// @endcond
+
+ public:
+
+ pair& operator=(const pair&) = delete;
+
+ /// Copy assignment operator
+ constexpr pair&
+ operator=(const pair& __p)
+ noexcept(_S_nothrow_assignable<const _T1&, const _T2&>())
+ requires (_S_assignable<const _T1&, const _T2&>())
+ {
+ first = __p.first;
+ second = __p.second;
+ return *this;
+ }
+
+ /// Move assignment operator
+ constexpr pair&
+ operator=(pair&& __p)
+ noexcept(_S_nothrow_assignable<_T1, _T2>())
+ requires (_S_assignable<_T1, _T2>())
+ {
+ first = std::forward<first_type>(__p.first);
+ second = std::forward<second_type>(__p.second);
+ return *this;
+ }
+
+ /// Converting assignment from a `pair<U1, U2>` lvalue
+ template<typename _U1, typename _U2>
+ constexpr pair&
+ operator=(const pair<_U1, _U2>& __p)
+ noexcept(_S_nothrow_assignable<const _U1&, const _U2&>())
+ requires (_S_assignable<const _U1&, const _U2&>())
+ {
+ first = __p.first;
+ second = __p.second;
+ return *this;
+ }
+
+ /// Converting assignment from a `pair<U1, U2>` rvalue
+ template<typename _U1, typename _U2>
+ constexpr pair&
+ operator=(pair<_U1, _U2>&& __p)
+ noexcept(_S_nothrow_assignable<_U1, _U2>())
+ requires (_S_assignable<_U1, _U2>())
+ {
+ first = std::forward<_U1>(__p.first);
+ second = std::forward<_U2>(__p.second);
+ return *this;
+ }
+#else
+ // C++11/14/17 implementation using enable_if, partially constexpr.
/** The default constructor creates @c first and @c second using their
* respective default constructors. */
explicit constexpr pair(const pair<_U1, _U2>& __p)
: first(__p.first), second(__p.second) { }
- constexpr pair(const pair&) = default; ///< Copy constructor
- constexpr pair(pair&&) = default; ///< Move constructor
-
#if _GLIBCXX_USE_DEPRECATED
private:
/// @cond undocumented
_GLIBCXX_DEPRECATED_SUGGEST("nullptr")
explicit pair(__null_ptr_constant, _U2&& __y)
: first(nullptr), second(std::forward<_U2>(__y)) { }
-#endif // _GLIBCXX_USE_DEPRECATED
+#endif
template<typename _U1, typename _U2, typename
enable_if<_PCCP::template
: first(std::forward<_U1>(__p.first)),
second(std::forward<_U2>(__p.second)) { }
- template<typename... _Args1, typename... _Args2>
- _GLIBCXX20_CONSTEXPR
- pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
-
- _GLIBCXX20_CONSTEXPR pair&
+ pair&
operator=(typename conditional<
__and_<is_copy_assignable<_T1>,
is_copy_assignable<_T2>>::value,
return *this;
}
- _GLIBCXX20_CONSTEXPR pair&
+ pair&
operator=(typename conditional<
__and_<is_move_assignable<_T1>,
is_move_assignable<_T2>>::value,
}
template<typename _U1, typename _U2>
- _GLIBCXX20_CONSTEXPR
typename enable_if<__and_<is_assignable<_T1&, const _U1&>,
is_assignable<_T2&, const _U2&>>::value,
pair&>::type
}
template<typename _U1, typename _U2>
- _GLIBCXX20_CONSTEXPR
typename enable_if<__and_<is_assignable<_T1&, _U1&&>,
is_assignable<_T2&, _U2&&>>::value,
pair&>::type
second = std::forward<_U2>(__p.second);
return *this;
}
-
- /// Swap the first members and then the second members.
- _GLIBCXX20_CONSTEXPR void
- swap(pair& __p)
- noexcept(__and_<__is_nothrow_swappable<_T1>,
- __is_nothrow_swappable<_T2>>::value)
- {
- using std::swap;
- swap(first, __p.first);
- swap(second, __p.second);
- }
-
- private:
- template<typename... _Args1, size_t... _Indexes1,
- typename... _Args2, size_t... _Indexes2>
- _GLIBCXX20_CONSTEXPR
- pair(tuple<_Args1...>&, tuple<_Args2...>&,
- _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>);
+#endif // lib concepts
#else
// C++03 implementation