[gcc r16-3574] libstdc++: Move _Binder and related aliases to separate file.

Tomasz Kaminski tkaminsk@gcc.gnu.org
Thu Sep 4 13:30:11 GMT 2025


https://gcc.gnu.org/g:b2adb7712cc57920d7d791c185dbf88e83b885c2

commit r16-3574-gb2adb7712cc57920d7d791c185dbf88e83b885c2
Author: Tomasz Kamiński <tkaminsk@redhat.com>
Date:   Mon Sep 1 14:28:17 2025 +0200

    libstdc++: Move _Binder and related aliases to separate file.
    
    bits/binders.h is already mapped in libstdc++-v3/doc/doxygen/stdheader.cc.
    
    libstdc++-v3/ChangeLog:
    
            * include/Makefile.am: Add bits/binders.h
            * include/Makefile.in: Add bits/binders.h
            * include/std/functional (std::_Indexed_bound_arg, std::_Binder)
            (std::__make_bound_args, std::_Bind_front_t, std::_Bind_back_t):
            Moved to bits/binders.h file, that is now included.
            * include/bits/binders.h: New file.
    
    Reviewed-by: Patrick Palka <ppalka@redhat.com>
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>

Diff:
---
 libstdc++-v3/include/Makefile.am    |   1 +
 libstdc++-v3/include/Makefile.in    |   1 +
 libstdc++-v3/include/bits/binders.h | 234 ++++++++++++++++++++++++++++++++++++
 libstdc++-v3/include/std/functional | 187 +---------------------------
 4 files changed, 237 insertions(+), 186 deletions(-)

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 6f5946970a89..0b0cbe2d3faf 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -191,6 +191,7 @@ bits_headers = \
 	${bits_srcdir}/basic_ios.tcc \
 	${bits_srcdir}/basic_string.h \
 	${bits_srcdir}/basic_string.tcc \
+	${bits_srcdir}/binders.h \
 	${bits_srcdir}/charconv.h \
 	${bits_srcdir}/chrono.h \
 	${bits_srcdir}/chrono_io.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 4b5917ebb4ae..e3a6d5f13905 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -544,6 +544,7 @@ bits_freestanding = \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/basic_ios.tcc \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/basic_string.h \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/basic_string.tcc \
+@GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/binders.h \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/charconv.h \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/chrono.h \
 @GLIBCXX_HOSTED_TRUE@	${bits_srcdir}/chrono_io.h \
diff --git a/libstdc++-v3/include/bits/binders.h b/libstdc++-v3/include/bits/binders.h
new file mode 100644
index 000000000000..c324bf51481c
--- /dev/null
+++ b/libstdc++-v3/include/bits/binders.h
@@ -0,0 +1,234 @@
+// Implementation of std::move_only_function, std::copyable_function
+// and std::function_ref  -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/binder.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_BINDERS_H
+#define _GLIBCXX_BINDERS_H 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#if __cplusplus >= 202002L
+
+#include <bits/invoke.h>
+#include <bits/move.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<size_t, typename _Tp>
+    struct _Indexed_bound_arg
+    {
+      [[no_unique_address]] _Tp _M_val;
+    };
+
+  template<typename... _IndexedArgs>
+    struct _Bound_arg_storage : _IndexedArgs...
+    {
+      template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs>
+	static constexpr
+	decltype(auto)
+	_S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args)
+	{
+	  if constexpr (_Back)
+	    return std::__invoke(std::forward<_Fd>(__fd),
+				 std::forward<_CallArgs>(__call_args)...,
+				 __like_t<_Self, _IndexedArgs>(__self)._M_val...);
+	  else
+	    return std::__invoke(std::forward<_Fd>(__fd),
+				 __like_t<_Self, _IndexedArgs>(__self)._M_val...,
+				 std::forward<_CallArgs>(__call_args)...);
+	}
+    };
+
+  template<typename... _BoundArgs, typename... _Args>
+    constexpr auto
+    __make_bound_args(_Args&&... __args)
+    {
+      if constexpr (sizeof...(_BoundArgs) == 1)
+	// pack has one element, so return copy of arg
+	return (_BoundArgs(std::forward<_Args>(__args)), ...);
+      else
+	{
+	  auto __impl = [&]<size_t... _Inds>(index_sequence<_Inds...>)
+	  {
+	    return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...>
+		   { {_BoundArgs(std::forward<_Args>(__args))}... };
+	  };
+	  return __impl(index_sequence_for<_BoundArgs...>());
+	}
+    }
+
+  template<bool _Back, typename _Fd, typename... _BoundArgs>
+    class _Binder
+    {
+      template<typename _Self, typename... _CallArgs>
+	using _Result_t = __conditional_t<
+	  _Back,
+	  invoke_result<__like_t<_Self, _Fd>,
+			_CallArgs..., __like_t<_Self, _BoundArgs>...>,
+	  invoke_result<__like_t<_Self, _Fd>,
+			__like_t<_Self, _BoundArgs>..., _CallArgs...>>::type;
+
+      template<typename _Self, typename... _CallArgs>
+	static consteval bool
+	_S_noexcept_invocable()
+	{
+	  if constexpr (_Back)
+	    return is_nothrow_invocable_v< __like_t<_Self, _Fd>,
+		     _CallArgs..., __like_t<_Self, _BoundArgs>...>;
+	  else
+	    return is_nothrow_invocable_v<__like_t<_Self, _Fd>,
+		     __like_t<_Self, _BoundArgs>..., _CallArgs...>;
+	}
+
+    public:
+      static_assert(is_move_constructible_v<_Fd>);
+      static_assert((is_move_constructible_v<_BoundArgs> && ...));
+
+      // First parameter is to ensure this constructor is never used
+      // instead of the copy/move constructor.
+      template<typename _Fn, typename... _Args>
+	explicit constexpr
+	_Binder(int, _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(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...))
+	{ static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
+
+#if __cpp_explicit_this_parameter
+      template<typename _Self, typename... _CallArgs>
+	constexpr _Result_t<_Self, _CallArgs...>
+	operator()(this _Self&& __self, _CallArgs&&... __call_args)
+	noexcept(_S_noexcept_invocable<_Self, _CallArgs...>())
+	{
+	  return _S_call(__like_t<_Self, _Binder>(__self),
+			 std::forward<_CallArgs>(__call_args)...);
+	}
+#else
+      template<typename... _CallArgs>
+	requires true
+	constexpr _Result_t<_Binder&, _CallArgs...>
+	operator()(_CallArgs&&... __call_args) &
+	noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>())
+	{
+	  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
+	}
+
+      template<typename... _CallArgs>
+	requires true
+	constexpr _Result_t<const _Binder&, _CallArgs...>
+	operator()(_CallArgs&&... __call_args) const &
+	noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>())
+	{
+	  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
+	}
+
+      template<typename... _CallArgs>
+	requires true
+	constexpr _Result_t<_Binder&&, _CallArgs...>
+	operator()(_CallArgs&&... __call_args) &&
+	noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>())
+	{
+	  return _S_call(std::move(*this),
+			 std::forward<_CallArgs>(__call_args)...);
+	}
+
+      template<typename... _CallArgs>
+	requires true
+	constexpr _Result_t<const _Binder&&, _CallArgs...>
+	operator()(_CallArgs&&... __call_args) const &&
+	noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>())
+	{
+	  return _S_call(std::move(*this),
+			 std::forward<_CallArgs>(__call_args)...);
+	}
+
+      template<typename... _CallArgs>
+	void operator()(_CallArgs&&...) & = delete;
+
+      template<typename... _CallArgs>
+	void operator()(_CallArgs&&...) const & = delete;
+
+      template<typename... _CallArgs>
+	void operator()(_CallArgs&&...) && = delete;
+
+      template<typename... _CallArgs>
+	void operator()(_CallArgs&&...) const && = delete;
+#endif
+
+    private:
+      using _BoundArgsStorage
+	// _BoundArgs are required to be move-constructible, so this is valid.
+	= decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...));
+
+      template<typename _Tp, typename... _CallArgs>
+	static constexpr
+	decltype(auto)
+	_S_call(_Tp&& __g, _CallArgs&&... __call_args)
+	{
+	  if constexpr (sizeof...(_BoundArgs) > 1)
+	    return _BoundArgsStorage::template _S_apply<_Back>(
+		      std::forward<_Tp>(__g)._M_fd,
+		      std::forward<_Tp>(__g)._M_bound_args,
+		      std::forward<_CallArgs>(__call_args)...);
+	  else if constexpr (sizeof...(_BoundArgs) == 0)
+	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
+				 std::forward<_CallArgs>(__call_args)...);
+	  else if constexpr (_Back) // sizeof...(_BoundArgs) == 1
+	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
+				 std::forward<_CallArgs>(__call_args)...,
+				 std::forward<_Tp>(__g)._M_bound_args);
+	  else // !_Back && sizeof...(_BoundArgs) == 1
+	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
+				 std::forward<_Tp>(__g)._M_bound_args,
+				 std::forward<_CallArgs>(__call_args)...);
+	}
+
+      [[no_unique_address]] _Fd _M_fd;
+      [[no_unique_address]] _BoundArgsStorage _M_bound_args;
+    };
+
+  template<typename _Fn, typename... _Args>
+    using _Bind_front_t = _Binder<false, decay_t<_Fn>, decay_t<_Args>...>;
+
+  // for zero bounds args behavior of bind_front and bind_back is the same,
+  // so reuse _Bind_front_t, i.e. _Binder<false, ...>
+  template<typename _Fn, typename... _Args>
+    using _Bind_back_t
+      = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // __cplusplus >= 202002L
+#endif // _GLIBCXX_BINDERS_H
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index ad2397613f41..5b329daf184e 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -84,6 +84,7 @@
 # include <bits/stl_algobase.h> // std::search
 #endif
 #if __cplusplus >= 202002L
+# include <bits/binders.h>
 # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc.
 # include <compare>
 #endif
@@ -921,192 +922,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 					  std::forward<_BoundArgs>(__args)...);
     }
 
-#if __cplusplus >= 202002L
-  template<size_t, typename _Tp>
-    struct _Indexed_bound_arg
-    {
-      [[no_unique_address]] _Tp _M_val;
-    };
-
-  template<typename... _IndexedArgs>
-    struct _Bound_arg_storage : _IndexedArgs...
-    {
-      template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs>
-	static constexpr
-	decltype(auto)
-	_S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args)
-	{
-	  if constexpr (_Back)
-	    return std::__invoke(std::forward<_Fd>(__fd),
-				 std::forward<_CallArgs>(__call_args)...,
-				 __like_t<_Self, _IndexedArgs>(__self)._M_val...);
-	  else
-	    return std::__invoke(std::forward<_Fd>(__fd),
-				 __like_t<_Self, _IndexedArgs>(__self)._M_val...,
-				 std::forward<_CallArgs>(__call_args)...);
-	}
-    };
-
-  template<typename... _BoundArgs, typename... _Args>
-    constexpr auto
-    __make_bound_args(_Args&&... __args)
-    {
-      if constexpr (sizeof...(_BoundArgs) == 1)
-	// pack has one element, so return copy of arg
-	return (_BoundArgs(std::forward<_Args>(__args)), ...);
-      else
-	{
-	  auto __impl = [&]<size_t... _Inds>(index_sequence<_Inds...>)
-	  {
-	    return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...>
-		   { {_BoundArgs(std::forward<_Args>(__args))}... };
-	  };
-	  return __impl(index_sequence_for<_BoundArgs...>());
-	}
-    }
-
-  template<bool _Back, typename _Fd, typename... _BoundArgs>
-    class _Binder
-    {
-      template<typename _Self, typename... _CallArgs>
-	using _Result_t = __conditional_t<
-	  _Back,
-	  invoke_result<__like_t<_Self, _Fd>,
-			_CallArgs..., __like_t<_Self, _BoundArgs>...>,
-	  invoke_result<__like_t<_Self, _Fd>,
-			__like_t<_Self, _BoundArgs>..., _CallArgs...>>::type;
-
-      template<typename _Self, typename... _CallArgs>
-	static consteval bool
-	_S_noexcept_invocable()
-	{
-	  if constexpr (_Back)
-	    return is_nothrow_invocable_v< __like_t<_Self, _Fd>,
-		     _CallArgs..., __like_t<_Self, _BoundArgs>...>;
-	  else
-	    return is_nothrow_invocable_v<__like_t<_Self, _Fd>,
-		     __like_t<_Self, _BoundArgs>..., _CallArgs...>;
-	}
-
-    public:
-      static_assert(is_move_constructible_v<_Fd>);
-      static_assert((is_move_constructible_v<_BoundArgs> && ...));
-
-      // First parameter is to ensure this constructor is never used
-      // instead of the copy/move constructor.
-      template<typename _Fn, typename... _Args>
-	explicit constexpr
-	_Binder(int, _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(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...))
-	{ static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
-
-#if __cpp_explicit_this_parameter
-      template<typename _Self, typename... _CallArgs>
-	constexpr _Result_t<_Self, _CallArgs...>
-	operator()(this _Self&& __self, _CallArgs&&... __call_args)
-	noexcept(_S_noexcept_invocable<_Self, _CallArgs...>())
-	{
-	  return _S_call(__like_t<_Self, _Binder>(__self),
-			 std::forward<_CallArgs>(__call_args)...);
-	}
-#else
-      template<typename... _CallArgs>
-	requires true
-	constexpr _Result_t<_Binder&, _CallArgs...>
-	operator()(_CallArgs&&... __call_args) &
-	noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>())
-	{
-	  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
-	}
-
-      template<typename... _CallArgs>
-	requires true
-	constexpr _Result_t<const _Binder&, _CallArgs...>
-	operator()(_CallArgs&&... __call_args) const &
-	noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>())
-	{
-	  return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
-	}
-
-      template<typename... _CallArgs>
-	requires true
-	constexpr _Result_t<_Binder&&, _CallArgs...>
-	operator()(_CallArgs&&... __call_args) &&
-	noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>())
-	{
-	  return _S_call(std::move(*this),
-			 std::forward<_CallArgs>(__call_args)...);
-	}
-
-      template<typename... _CallArgs>
-	requires true
-	constexpr _Result_t<const _Binder&&, _CallArgs...>
-	operator()(_CallArgs&&... __call_args) const &&
-	noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>())
-	{
-	  return _S_call(std::move(*this),
-			 std::forward<_CallArgs>(__call_args)...);
-	}
-
-      template<typename... _CallArgs>
-	void operator()(_CallArgs&&...) & = delete;
-
-      template<typename... _CallArgs>
-	void operator()(_CallArgs&&...) const & = delete;
-
-      template<typename... _CallArgs>
-	void operator()(_CallArgs&&...) && = delete;
-
-      template<typename... _CallArgs>
-	void operator()(_CallArgs&&...) const && = delete;
-#endif
-
-    private:
-      using _BoundArgsStorage
-	// _BoundArgs are required to be move-constructible, so this is valid.
-	= decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...));
-
-      template<typename _Tp, typename... _CallArgs>
-	static constexpr
-	decltype(auto)
-	_S_call(_Tp&& __g, _CallArgs&&... __call_args)
-	{
-	  if constexpr (sizeof...(_BoundArgs) > 1)
-	    return _BoundArgsStorage::template _S_apply<_Back>(
-		      std::forward<_Tp>(__g)._M_fd,
-		      std::forward<_Tp>(__g)._M_bound_args,
-		      std::forward<_CallArgs>(__call_args)...);
-	  else if constexpr (sizeof...(_BoundArgs) == 0)
-	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
-				 std::forward<_CallArgs>(__call_args)...);
-	  else if constexpr (_Back) // sizeof...(_BoundArgs) == 1
-	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
-				 std::forward<_CallArgs>(__call_args)...,
-				 std::forward<_Tp>(__g)._M_bound_args);
-	  else // !_Back && sizeof...(_BoundArgs) == 1
-	    return std::__invoke(std::forward<_Tp>(__g)._M_fd,
-				 std::forward<_Tp>(__g)._M_bound_args,
-				 std::forward<_CallArgs>(__call_args)...);
-
-	}
-
-      [[no_unique_address]] _Fd _M_fd;
-      [[no_unique_address]] _BoundArgsStorage _M_bound_args;
-    };
-
-  template<typename _Fn, typename... _Args>
-    using _Bind_front_t = _Binder<false, decay_t<_Fn>, decay_t<_Args>...>;
-
-  // for zero bounds args behavior of bind_front and bind_back is the same,
-  // so reuse _Bind_front_t, i.e. _Binder<false, ...>
-  template<typename _Fn, typename... _Args>
-    using _Bind_back_t
-      = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>;
-#endif // __cplusplus >= 202002L
-
 #ifdef __cpp_lib_bind_front // C++ >= 20
   /** Create call wrapper by partial application of arguments to function.
    *


More information about the Libstdc++-cvs mailing list