public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-221] libstdc++: Simplify std::pair constraints using concepts Date: Wed, 28 Apr 2021 16:57:06 +0000 (GMT) [thread overview] Message-ID: <20210428165706.20F9E3AA981B@sourceware.org> (raw) https://gcc.gnu.org/g:e1543e694dadf1ea70eb72325219bc0cdc914a35 commit r12-221-ge1543e694dadf1ea70eb72325219bc0cdc914a35 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Apr 28 17:46:01 2021 +0100 libstdc++: Simplify std::pair constraints using concepts This re-implements the constraints on the std::pair constructors and assignment operators in C++20 mode, to use concepts. The non-standard constructors deprecated for PR 99957 are no longer supported in C++20 mode, which requires some minor testsuite changes. Otherwise all tests pass in C++20 mode. libstdc++-v3/ChangeLog: * include/bits/stl_pair.h (pair) [__cplusplus > 202002]: Add new definitions for constructors and assignment operators using concepts for constraints. * testsuite/20_util/pair/cons/99957.cc: Disable for C++20 and later. * testsuite/20_util/pair/cons/explicit_construct.cc: Adjust expected error messages to also match C++20 errors. Diff: --- libstdc++-v3/include/bits/stl_pair.h | 221 ++++++++++++++++++--- libstdc++-v3/testsuite/20_util/pair/cons/99957.cc | 2 +- .../20_util/pair/cons/explicit_construct.cc | 8 +- 3 files changed, 193 insertions(+), 38 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 883d7441b3d..c89f377fddc 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -92,6 +92,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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 @@ -171,11 +172,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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; @@ -196,7 +198,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ 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 @@ -205,7 +207,186 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _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. */ @@ -281,9 +462,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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 @@ -341,7 +519,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _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 @@ -382,11 +560,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : 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, @@ -397,7 +571,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - _GLIBCXX20_CONSTEXPR pair& + pair& operator=(typename conditional< __and_<is_move_assignable<_T1>, is_move_assignable<_T2>>::value, @@ -411,7 +585,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _U1, typename _U2> - _GLIBCXX20_CONSTEXPR typename enable_if<__and_<is_assignable<_T1&, const _U1&>, is_assignable<_T2&, const _U2&>>::value, pair&>::type @@ -423,7 +596,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _U1, typename _U2> - _GLIBCXX20_CONSTEXPR typename enable_if<__and_<is_assignable<_T1&, _U1&&>, is_assignable<_T2&, _U2&&>>::value, pair&>::type @@ -433,24 +605,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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 diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc index d75ff21da60..150bcd57c9a 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/99957.cc @@ -1,5 +1,5 @@ // { dg-options "-Wdeprecated" } -// { dg-do compile { target c++11 } } +// { dg-do compile { target { c++11 && { ! c++20 } } } } #include <utility> diff --git a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc index 508ca32ecb7..ecd5acf9375 100644 --- a/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc +++ b/libstdc++-v3/testsuite/20_util/pair/cons/explicit_construct.cc @@ -83,12 +83,12 @@ void f7(std::pair<long, long>) {} std::pair<ExplicitDefault, int> f8() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } std::pair<ExplicitDefaultDefault, int> f9() { - return {}; // { dg-error "could not convert" } + return {}; // { dg-error "convert" } } void f10(std::pair<ExplicitDefault, int>) {} @@ -107,8 +107,8 @@ void test_arg_passing() f7({1,2}); f7(std::pair<int, int>{}); f7(std::pair<long, long>{}); - f10({}); // { dg-error "could not convert" } - f11({}); // { dg-error "could not convert" } + f10({}); // { dg-error "convert" } + f11({}); // { dg-error "convert" } f10(std::pair<ExplicitDefault, int>{}); f11(std::pair<ExplicitDefaultDefault, int>{}); }
reply other threads:[~2021-04-28 16:57 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210428165706.20F9E3AA981B@sourceware.org \ --to=redi@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).