[RFC] Deprecate non-standard constructors in std::pair

Jonathan Wakely jwakely@redhat.com
Wed Apr 7 18:17:13 GMT 2021


On 07/04/21 19:00 +0100, Jonathan Wakely wrote:
>On 07/04/21 17:59 +0100, Jonathan Wakely wrote:
>>On 07/04/21 13:46 +0100, Jonathan Wakely wrote:
>>>On 07/04/21 15:41 +0300, Ville Voutilainen via Libstdc++ wrote:
>>>>On Wed, 7 Apr 2021 at 15:31, Jonathan Wakely via Libstdc++
>>>><libstdc++@gcc.gnu.org> wrote:
>>>>>I propose that we deprecate the constructors for C++11/14/17/20 in
>>>>>stage 1, and do not support them at all in C++23 mode once P1951 is
>>>>>supported. I have a patch which I'll send in stage 1 (it also uses
>>>>>C++20 concepts to simplify std::pair and fix PR 97930).
>>>>>
>>>>>After a period of deprecation we could remove them, and support P1951
>>>>>for -std=gnu++11/14/17/20 too so that {} continues to work.
>>>>
>>>>The proposal sounds good to me.
>>>
>>>Thanks. I've created https://gcc.gnu.org/PR99957 so I don't forget.
>>
>>Here's a patch to implement it, for stage 1.
>
>
>>diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h
>>index 70262f9508f..883d7441b3d 100644
>>--- a/libstdc++-v3/include/bits/stl_pair.h
>>+++ b/libstdc++-v3/include/bits/stl_pair.h
>>@@ -128,34 +128,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>		      is_convertible<_U2&&, _T2>>::value;
>>      }
>>
>>-      template <bool __implicit, typename _U1, typename _U2>
>>-      static constexpr bool _CopyMovePair()
>>-      {
>>-	using __do_converts = __and_<is_convertible<const _U1&, _T1>,
>>-				  is_convertible<_U2&&, _T2>>;
>>-	using __converts = typename conditional<__implicit,
>>-				       __do_converts,
>>-				       __not_<__do_converts>>::type;
>>-	return __and_<is_constructible<_T1, const _U1&>,
>>-		      is_constructible<_T2, _U2&&>,
>>-		      __converts
>>-		      >::value;
>>-      }
>>
>>      template <bool __implicit, typename _U1, typename _U2>
>>-      static constexpr bool _MoveCopyPair()
>>+      static constexpr bool _DeprConsPair()
>>      {
>>	using __do_converts = __and_<is_convertible<_U1&&, _T1>,
>>-				  is_convertible<const _U2&, _T2>>;
>>+				     is_convertible<_U2&&, _T2>>;
>>	using __converts = typename conditional<__implicit,
>>-				       __do_converts,
>>-				       __not_<__do_converts>>::type;
>>+						__do_converts,
>>+						__not_<__do_converts>>::type;
>>	return __and_<is_constructible<_T1, _U1&&>,
>>-		      is_constructible<_T2, const _U2&&>,
>>+		      is_constructible<_T2, _U2&&>,
>
>N.B. this fixes a bug in the line above, where const _U2&& is used in
>place of const _U2&.
>
>I'll create a testcase that tickles the bug and report it to bugzilla
>tomorrow.

This fails to compile because of that bug:

#include <utility>

struct X {
   X(void* = 0) { }
   X(const X&) = default;
   X(const X&&) = delete;
};

struct move_only {
   move_only() = default;
   move_only(move_only&&) = default;
};

std::pair<move_only, X> p0(move_only(), 0);
std::pair<move_only, X> p1(move_only(), {});

The pair(U1&&, const T2&) constructor should be viable, but it fails
the _MoveCopyPair constraint check because X(const X&&) is deleted.

I'm not sure I care about this though. It would only work because of
those non-standard constructors which we're talking about deprecating.
I'm not very motivated to fix them so they accept this, when we're
going to deprecate them anyway.



More information about the Libstdc++ mailing list