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] P0356R5 Simplified partial function application


On 07/03/19 14:15 +0000, Jonathan Wakely wrote:
	* include/std/functional [C++20] (_Bind_front, _Bind_front_t): Define
	helpers for bind_front.
	(bind_front, __cpp_lib_bind_front): Define.
	* testsuite/20_util/function_objects/bind_front/1.cc: New test.

I'm considering something like the attached patch (but with better
names for __tag1 and __tag2 obviously). With this change bind_front
would unwrap nested binders, so that bind_front(bind_front(f, 1), 2)
would create a _Bind_front<F, int, int> instead of
_Bind_front<_Bind_front<F, int>, int>.

That would make the call go straight to the target object, instead of
through an extra layer of wrapper (which should improve compile times,
and also unoptimized runtime performance).



diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 8cf2c670648..da61b00bd15 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -839,6 +839,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus > 201703L
 #define __cpp_lib_bind_front 201902L
 
+  struct __tag1;
+  struct __tag2;
+
   template<typename _Fd, typename... _BoundArgs>
     struct _Bind_front
     {
@@ -849,13 +852,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // instead of the copy/move constructor.
       template<typename _Fn, typename... _Args>
 	explicit constexpr
-	_Bind_front(int, _Fn&& __fn, _Args&&... __args)
+	_Bind_front(__tag1*, _Fn&& __fn, _Args&&... __args)
 	noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
 			is_nothrow_constructible<_BoundArgs, _Args>...>::value)
 	: _M_fd(std::forward<_Fn>(__fn)),
 	  _M_bound_args(std::forward<_Args>(__args)...)
 	{ static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
 
+      template<typename... _BArgs, typename... _Args>
+	explicit constexpr
+	_Bind_front(__tag2*, const _Bind_front<_Fd, _BArgs...>& __fn,
+		    _Args&&... __args)
+	: _M_fd(__fn._M_fd),
+	  _M_bound_args(std::tuple_cat(__fn._M_bound_args,
+		std::make_tuple(std::forward<_Args>(__args)...)))
+	{ }
+
+      template<typename... _BArgs, typename... _Args>
+	explicit constexpr
+	_Bind_front(__tag2*, _Bind_front<_Fd, _BArgs...>&& __fn,
+		    _Args&&... __args)
+	: _M_fd(std::move(__fn._M_fd)),
+	  _M_bound_args(std::tuple_cat(std::move(__fn._M_bound_args),
+		std::make_tuple(std::forward<_Args>(__args)...)))
+	{ }
+
       _Bind_front(const _Bind_front&) = default;
       _Bind_front(_Bind_front&&) = default;
       _Bind_front& operator=(const _Bind_front&) = default;
@@ -919,19 +940,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Fd _M_fd;
       std::tuple<_BoundArgs...> _M_bound_args;
+
+      template<typename _Fd2, typename... _BArgs>
+	friend class _Bind_front;
     };
 
   template<typename _Fn, typename... _Args>
-    using _Bind_front_t
-      = _Bind_front<decay_t<_Fn>, unwrap_ref_decay_t<_Args>...>;
+    struct _Bind_front_helper
+    {
+      using type = _Bind_front<_Fn, _Args...>;
+      using __tag = __tag1*;
+    };
+
+  template<typename _Fn, typename... _BoundArgs, typename... _Args>
+    struct _Bind_front_helper<_Bind_front<_Fn, _BoundArgs...>, _Args...>
+    {
+      using type = _Bind_front<_Fn, _BoundArgs..., _Args...>;
+      using __tag = __tag2*;
+    };
+
+  template<typename _Fn, typename... _Args>
+    using _Bind_front_t = typename
+      _Bind_front_helper<decay_t<_Fn>, unwrap_ref_decay_t<_Args>...>::type;
+
+  template<typename _Fn, typename... _Args>
+    using _Bind_front_tag = typename
+      _Bind_front_helper<decay_t<_Fn>, unwrap_ref_decay_t<_Args>...>::__tag;
 
   template<typename _Fn, typename... _Args>
     _Bind_front_t<_Fn, _Args...>
     bind_front(_Fn&& __fn, _Args&&... __args)
-    noexcept(is_nothrow_constructible_v<int, _Bind_front_t<_Fn, _Args...>,
+    noexcept(is_nothrow_constructible_v<_Bind_front_tag<_Fn, _Args...>,
+					_Bind_front_t<_Fn, _Args...>,
 					_Fn, _Args...>)
     {
-      return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
+      return _Bind_front_t<_Fn, _Args...>(_Bind_front_tag<_Fn, _Args...>(),
+					  std::forward<_Fn>(__fn),
 					  std::forward<_Args>(__args)...);
     }
 #endif

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