This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] C++2a Utility functions to implement uses-allocator construction (P0591R4)


On 01/03/19 14:06 +0000, Jonathan Wakely wrote:
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 ...

[...]

+	  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)...);
+	    }

I tried replacing this lambda with:

	  using _Targs = tuple<_Args&&...>;
	  _Targs __targs{std::forward<_Args>(__args)...};

         using _Args_0 = tuple_element_t<0, _Targs>;
         using _Args_1 = tuple_element_t<1, _Targs>;

         return std::make_tuple(piecewise_construct,
             std::__uses_alloc_args<_Tp1>(__a,
               std::forward<_Args_0>(std::get<0>(__targs))),
             std::__uses_alloc_args<_Tp2>(__a,
               std::forward<_Args_1>(std::get<1>(__targs))));

And similarly for the sizeof...(__args))==3 case.  Which seems more
straightforward, unfortunately it compiles measurably slower, using
more memory. The optimized code is the same size, but unoptimized the
lambda version is a bit smaller.

The current code on trunk compiles fastest, by quite a big margin.
That surprises me as I thought a single function using if-constexpr
would outperform several overloads constrained via SFINAE.

Being able to use __uses_alloc_args in C++17 might be worth the extra
compile-time cost though. I'll keep thinking about it.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]