On 01/03/19 13:50 +0000, Jonathan Wakely wrote:
        * include/std/memory (uses_allocator_construction_args): New set of
        overloaded functions.
        (make_obj_using_allocator, uninitialized_construct_using_allocator):
        New functions.
        * include/std/memory_resource (polymorphic_allocator::construct)
        [__cplusplus > 201703l]: Replace all overloads with a single function
        using uses_allocator_construction_args.
        * testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New
        test.
        * testsuite/20_util/uses_allocator/make_obj.cc: New test.

If we don't care about providing the exact signatures from the C++2a
draft, we could do this and use it in C++17 as well ...



diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 00a85eef25e..045974a1b46 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -168,7 +168,7 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; }
     }
 #endif // C++2a
 
-#if __cplusplus > 201703L
+#if __cplusplus >= 201703L
   template<typename _Tp>
     struct __is_pair : false_type { };
   template<typename _Tp, typename _Up>
@@ -176,167 +176,94 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; }
   template<typename _Tp, typename _Up>
     struct __is_pair<const pair<_Tp, _Up>> : true_type { };
 
-  template<typename _Tp, typename __ = _Require<__not_<__is_pair<_Tp>>>,
-	   typename _Alloc, typename... _Args>
+  // Equivalent of uses_allocator_construction_args for internal use in C++17
+  template<typename _Tp, typename _Alloc, typename... _Args>
     constexpr auto
     __uses_alloc_args(const _Alloc& __a, _Args&&... __args) noexcept
     {
-      if constexpr (uses_allocator_v<remove_cv_t<_Tp>, _Alloc>)
+      if constexpr (!__is_pair<_Tp>::value)
 	{
-	  if constexpr (is_constructible_v<_Tp, allocator_arg_t,
-					   const _Alloc&, _Args...>)
+	  if constexpr (uses_allocator_v<remove_cv_t<_Tp>, _Alloc>)
 	    {
-	      return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(
-		  allocator_arg, __a, std::forward<_Args>(__args)...);
+	      if constexpr (is_constructible_v<_Tp, allocator_arg_t,
+		  const _Alloc&, _Args...>)
+		{
+		  return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(
+		      allocator_arg, __a, std::forward<_Args>(__args)...);
+		}
+	      else
+		{
+		  static_assert(
+		      is_constructible_v<_Tp, _Args..., const _Alloc&>);
+
+		  return tuple<_Args&&..., const _Alloc&>(
+		      std::forward<_Args>(__args)..., __a);
+		}
 	    }
 	  else
 	    {
-	      static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>);
+	      static_assert(is_constructible_v<_Tp, _Args...>);
 
-	      return tuple<_Args&&..., const _Alloc&>(
-		  std::forward<_Args>(__args)..., __a);
+	      return tuple<_Args&&...>(std::forward<_Args>(__args)...);
 	    }
 	}
       else
 	{
-	  static_assert(is_constructible_v<_Tp, _Args...>);
-
-	  return tuple<_Args&&...>(std::forward<_Args>(__args)...);
-	}
-    }
-
-#if __cpp_concepts
-  template<typename _Tp>
-    concept bool _Std_pair = __is_pair<_Tp>::value;
-#endif
-
-// This is a temporary workaround until -fconcepts is implied by -std=gnu++2a
-#if __cpp_concepts
-# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) _Std_pair T
-# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) _Std_pair T
-#else
-# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) \
-      typename T, typename __ = _Require<__is_pair<T>>
-# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) typename T, typename
-#endif
-
-  template<typename _Tp,
-#if ! __cpp_concepts
-	   typename __ = _Require<__not_<__is_pair<_Tp>>>,
-#endif
-	   typename _Alloc, typename... _Args>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a,
-				     _Args&&... __args) noexcept
-#if __cpp_concepts
-    requires ! _Std_pair<_Tp>
-#endif
-    {
-      return std::__uses_alloc_args<_Tp>(__a, std::forward<_Args>(__args)...);
-    }
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
-	   typename _Tuple1, typename _Tuple2>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
-				     _Tuple1&& __x, _Tuple2&& __y) noexcept;
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc&) noexcept;
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc&, _Up&&, _Vp&&) noexcept;
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc&,
-				     const pair<_Up, _Vp>&) noexcept;
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept;
+	  static_assert(sizeof...(__args) <= 3);
 
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
-	   typename _Tuple1, typename _Tuple2>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
-				     _Tuple1&& __x, _Tuple2&& __y) noexcept
-    {
-      using _Tp1 = typename _Tp::first_type;
-      using _Tp2 = typename _Tp::second_type;
-
-      return std::make_tuple(piecewise_construct,
-	  std::apply([&__a](auto&&... __args1) {
-	      return std::uses_allocator_construction_args<_Tp1>(
-		  __a, std::forward<decltype(__args1)>(__args1)...);
-	  }, std::forward<_Tuple1>(__x)),
-	  std::apply([&__a](auto&&... __args2) {
-	      return std::uses_allocator_construction_args<_Tp2>(
-		  __a, std::forward<decltype(__args2)>(__args2)...);
-	  }, std::forward<_Tuple2>(__y)));
-    }
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a) noexcept
-    {
-      using _Tp1 = typename _Tp::first_type;
-      using _Tp2 = typename _Tp::second_type;
-
-      return std::make_tuple(piecewise_construct,
-	  std::uses_allocator_construction_args<_Tp1>(__a),
-	  std::uses_allocator_construction_args<_Tp2>(__a));
-    }
+	  using _Tp1 = typename _Tp::first_type;
+	  using _Tp2 = typename _Tp::second_type;
 
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a, _Up&& __u, _Vp&& __v)
-      noexcept
-    {
-      using _Tp1 = typename _Tp::first_type;
-      using _Tp2 = typename _Tp::second_type;
-
-      return std::make_tuple(piecewise_construct,
-	  std::uses_allocator_construction_args<_Tp1>(__a,
-	    std::forward<_Up>(__u)),
-	  std::uses_allocator_construction_args<_Tp2>(__a,
-	    std::forward<_Vp>(__v)));
-    }
-
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
-    constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a,
-				     const pair<_Up, _Vp>& __pr) noexcept
-    {
-      using _Tp1 = typename _Tp::first_type;
-      using _Tp2 = typename _Tp::second_type;
-
-      return std::make_tuple(piecewise_construct,
-	  std::uses_allocator_construction_args<_Tp1>(__a, __pr.first),
-	  std::uses_allocator_construction_args<_Tp2>(__a, __pr.second));
+	  if constexpr (sizeof...(__args) == 0)
+	    {
+	      return std::make_tuple(piecewise_construct,
+		  std::__uses_alloc_args<_Tp1>(__a),
+		  std::__uses_alloc_args<_Tp2>(__a));
+	    }
+	  else if constexpr (sizeof...(__args) == 1)
+	    {
+	      return std::make_tuple(piecewise_construct,
+		  std::__uses_alloc_args<_Tp1>(__a,
+		    std::forward<_Args>(__args).first...),
+		  std::__uses_alloc_args<_Tp2>(__a,
+		    std::forward<_Args>(__args).second...));
+	    }
+	  else if constexpr (sizeof...(__args) == 2)
+	    {
+	      return [&](auto&& __arg1, auto&& __arg2)
+		{
+		  return std::make_tuple(piecewise_construct,
+		      std::__uses_alloc_args<_Tp1>(__a,
+			std::forward<decltype(__arg1)>(__arg1)),
+		      std::__uses_alloc_args<_Tp2>(__a,
+			std::forward<decltype(__arg2)>(__arg2)));
+		}(std::forward<_Args>(__args)...);
+	    }
+	  else if constexpr (sizeof...(__args) == 3)
+	    {
+	      return [&](piecewise_construct_t, auto&& __arg1, auto&& __arg2)
+		{
+		  return std::make_tuple(piecewise_construct,
+		      std::apply([&](auto&&... __args1) {
+			  return std::__uses_alloc_args<_Tp1>(__a,
+			      std::forward<decltype(__args1)>(__args1)...);
+		      }, std::forward<decltype(__arg1)>(__arg1)),
+		      std::apply([&](auto&&... __args2) {
+			  return std::__uses_alloc_args<_Tp2>(__a,
+			      std::forward<decltype(__args2)>(__args2)...);
+		      }, std::forward<decltype(__arg2)>(__arg2)));
+		}(std::forward<_Args>(__args)...);
+	    }
+	}
     }
 
-  template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
-	   typename _Up, typename _Vp>
+#if __cplusplus > 201703L
+  template<typename _Tp, typename _Alloc, typename... _Args>
     constexpr auto
-    uses_allocator_construction_args(const _Alloc& __a,
-				     pair<_Up, _Vp>&& __pr) noexcept
+    uses_allocator_construction_args(const _Alloc& __a, _Args&&... __args)
     {
-      using _Tp1 = typename _Tp::first_type;
-      using _Tp2 = typename _Tp::second_type;
-
-      return std::make_tuple(piecewise_construct,
-	  std::uses_allocator_construction_args<_Tp1>(__a,
-	    std::move(__pr).first),
-	  std::uses_allocator_construction_args<_Tp2>(__a,
-	    std::move(__pr).second));
+      return std::__uses_alloc_args<_Tp>(__a,
+	  std::forward<_Args>(__args)...);
     }
 
   template<typename _Tp, typename _Alloc, typename... _Args>
@@ -356,8 +283,8 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; }
       return ::new(__vp) _Tp(std::make_obj_using_allocator<_Tp>(__a,
 	    std::forward<_Args>(__args)...));
     }
-
 #endif // C++2a
+#endif // C++17
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index a212bccc9b1..3ea6990ecae 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -124,14 +124,6 @@ namespace pmr
   template<typename _Tp>
     class polymorphic_allocator
     {
-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
-      // 2975. Missing case for pair construction in polymorphic allocators
-      template<typename _Up>
-	struct __not_pair { using type = void; };
-
-      template<typename _Up1, typename _Up2>
-	struct __not_pair<pair<_Up1, _Up2>> { };
-
     public:
       using value_type = _Tp;
 
@@ -170,89 +162,15 @@ namespace pmr
       __attribute__((__nonnull__))
       { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
 
-#if __cplusplus <= 201703L
-      template<typename _Tp1, typename... _Args>
-	__attribute__((__nonnull__))
-	typename __not_pair<_Tp1>::type
-	construct(_Tp1* __p, _Args&&... __args)
-	{
-	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
-	  // 2969. polymorphic_allocator::construct() shouldn't pass resource()
-	  using __use_tag
-	    = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
-	  if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
-	    ::new(__p) _Tp1(std::forward<_Args>(__args)...);
-	  else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
-	    ::new(__p) _Tp1(allocator_arg, *this,
-			    std::forward<_Args>(__args)...);
-	  else
-	    ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
-	}
-
-      template<typename _Tp1, typename _Tp2,
-	       typename... _Args1, typename... _Args2>
-	__attribute__((__nonnull__))
-	void
-	construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
-		  tuple<_Args1...> __x, tuple<_Args2...> __y)
-	{
-	  auto __x_tag =
-	    __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
-	  auto __y_tag =
-	    __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
-	  index_sequence_for<_Args1...> __x_i;
-	  index_sequence_for<_Args2...> __y_i;
-
-	  ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
-				      _S_construct_p(__x_tag, __x_i, __x),
-				      _S_construct_p(__y_tag, __y_i, __y));
-	}
-
-      template<typename _Tp1, typename _Tp2>
-	__attribute__((__nonnull__))
-	void
-	construct(pair<_Tp1, _Tp2>* __p)
-	{ this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
-
-      template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
-	__attribute__((__nonnull__))
-	void
-	construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
-	{
-	  this->construct(__p, piecewise_construct,
-			  forward_as_tuple(std::forward<_Up>(__x)),
-			  forward_as_tuple(std::forward<_Vp>(__y)));
-	}
-
-      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
-	__attribute__((__nonnull__))
-	void
-	construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
-	{
-	  this->construct(__p, piecewise_construct,
-			  forward_as_tuple(__pr.first),
-			  forward_as_tuple(__pr.second));
-	}
-
-      template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
-	__attribute__((__nonnull__))
-	void
-	construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
-	{
-	  this->construct(__p, piecewise_construct,
-			  forward_as_tuple(std::forward<_Up>(__pr.first)),
-			  forward_as_tuple(std::forward<_Vp>(__pr.second)));
-	}
-#else
       template<typename _Tp1, typename... _Args>
 	__attribute__((__nonnull__))
 	void
 	construct(_Tp1* __p, _Args&&... __args)
 	{
-	  std::uninitialized_construct_using_allocator(__p, *this,
-	      std::forward<_Args>(__args)...);
+	  ::new ((void*)__p) _Tp1(std::make_from_tuple<_Tp1>(
+		std::__uses_alloc_args<_Tp1>(*this,
+		  std::forward<_Args>(__args)...)));
 	}
-#endif
 
       template<typename _Up>
 	__attribute__((__nonnull__))
@@ -270,30 +188,6 @@ namespace pmr
       { return _M_resource; }
 
     private:
-      using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
-      using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
-
-      template<typename _Ind, typename... _Args>
-	static tuple<_Args&&...>
-	_S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
-	{ return std::move(__t); }
-
-      template<size_t... _Ind, typename... _Args>
-	static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
-	_S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
-		       tuple<_Args...>& __t)
-	{
-	  return {
-	      allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
-	  };
-	}
-
-      template<size_t... _Ind, typename... _Args>
-	static tuple<_Args&&..., polymorphic_allocator>
-	_S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
-		       tuple<_Args...>& __t)
-	{ return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
-
       memory_resource* _M_resource;
     };
 

Reply via email to