libstdc++: binders.h Source File

libstdc++

bits/binders.h
Go to the documentation of this file.
1// Implementation of std::move_only_function, std::copyable_function
2// and std::function_ref -*- C++ -*-
3
4// Copyright The GNU Toolchain Authors.
5//
6// This file is part of the GNU ISO C++ Library. This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 3, or (at your option)
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
20
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24// <http://www.gnu.org/licenses/>.
25
26/** @file include/bits/binders.h
27 * This is an internal header file, included by other library headers.
28 * Do not attempt to use it directly. @headername{functional}
29 */
30
31#ifndef _GLIBCXX_BINDERS_H
32#define _GLIBCXX_BINDERS_H 1
33
34#ifdef _GLIBCXX_SYSHDR
35#pragma GCC system_header
36#endif
37
38#if __cplusplus >= 202002L
39
40#include <bits/invoke.h>
41#include <bits/move.h>
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47 template<size_t, typename _Tp>
48 struct _Indexed_bound_arg
49 {
50 [[no_unique_address]] _Tp _M_val;
51 };
52
53 template<typename... _IndexedArgs>
54 struct _Bound_arg_storage : _IndexedArgs...
55 {
56 template<bool _Back, typename _Fd, typename _Self, typename... _CallArgs>
57 static constexpr
58 decltype(auto)
59 _S_apply(_Fd&& __fd, _Self&& __self, _CallArgs&&... __call_args)
60 {
61 if constexpr (_Back)
62 return std::__invoke(std::forward<_Fd>(__fd),
63 std::forward<_CallArgs>(__call_args)...,
64 __like_t<_Self, _IndexedArgs>(__self)._M_val...);
65 else
66 return std::__invoke(std::forward<_Fd>(__fd),
67 __like_t<_Self, _IndexedArgs>(__self)._M_val...,
68 std::forward<_CallArgs>(__call_args)...);
69 }
70 };
71
72 template<typename... _BoundArgs, typename... _Args>
73 constexpr auto
74 __make_bound_args(_Args&&... __args)
75 {
76 if constexpr (sizeof...(_BoundArgs) == 1)
77 // pack has one element, so return copy of arg
78 return (_BoundArgs(std::forward<_Args>(__args)), ...);
79 else
80 {
81 auto __impl = [&]<size_t... _Inds>(index_sequence<_Inds...>)
82 {
83 return _Bound_arg_storage<_Indexed_bound_arg<_Inds, _BoundArgs>...>
84 { {_BoundArgs(std::forward<_Args>(__args))}... };
85 };
86 return __impl(index_sequence_for<_BoundArgs...>());
87 }
88 }
89
90 template<bool _Back, typename _Fd, typename... _BoundArgs>
91 class _Binder
92 {
93 template<typename _Self, typename... _CallArgs>
94 using _Result_t = __conditional_t<
95 _Back,
96 invoke_result<__like_t<_Self, _Fd>,
97 _CallArgs..., __like_t<_Self, _BoundArgs>...>,
98 invoke_result<__like_t<_Self, _Fd>,
99 __like_t<_Self, _BoundArgs>..., _CallArgs...>>::type;
100
101 template<typename _Self, typename... _CallArgs>
102 static consteval bool
103 _S_noexcept_invocable()
104 {
105 if constexpr (_Back)
106 return is_nothrow_invocable_v< __like_t<_Self, _Fd>,
107 _CallArgs..., __like_t<_Self, _BoundArgs>...>;
108 else
109 return is_nothrow_invocable_v<__like_t<_Self, _Fd>,
110 __like_t<_Self, _BoundArgs>..., _CallArgs...>;
111 }
112
113 public:
114 static_assert(is_move_constructible_v<_Fd>);
115 static_assert((is_move_constructible_v<_BoundArgs> && ...));
116
117 // First parameter is to ensure this constructor is never used
118 // instead of the copy/move constructor.
119 template<typename _Fn, typename... _Args>
120 explicit constexpr
121 _Binder(int, _Fn&& __fn, _Args&&... __args)
122 noexcept(__and_<is_nothrow_constructible<_Fd, _Fn>,
123 is_nothrow_constructible<_BoundArgs, _Args>...>::value)
124 : _M_fd(std::forward<_Fn>(__fn)),
125 _M_bound_args(__make_bound_args<_BoundArgs...>(std::forward<_Args>(__args)...))
126 { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
127
128#if _GLIBCXX_EXPLICIT_THIS_PARAMETER
129# pragma GCC diagnostic push
130# pragma GCC diagnostic ignored "-Wc++23-extensions" // deducing this
131 template<typename _Self, typename... _CallArgs>
132 constexpr _Result_t<_Self, _CallArgs...>
133 operator()(this _Self&& __self, _CallArgs&&... __call_args)
134 noexcept(_S_noexcept_invocable<_Self, _CallArgs...>())
135 {
136 return _S_call(__like_t<_Self, _Binder>(__self),
137 std::forward<_CallArgs>(__call_args)...);
138 }
139# pragma GCC diagnostic pop
140#else
141 template<typename... _CallArgs>
142 requires true
143 constexpr _Result_t<_Binder&, _CallArgs...>
144 operator()(_CallArgs&&... __call_args) &
145 noexcept(_S_noexcept_invocable<_Binder&, _CallArgs...>())
146 {
147 return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
148 }
149
150 template<typename... _CallArgs>
151 requires true
152 constexpr _Result_t<const _Binder&, _CallArgs...>
153 operator()(_CallArgs&&... __call_args) const &
154 noexcept(_S_noexcept_invocable<const _Binder&, _CallArgs...>())
155 {
156 return _S_call(*this, std::forward<_CallArgs>(__call_args)...);
157 }
158
159 template<typename... _CallArgs>
160 requires true
161 constexpr _Result_t<_Binder&&, _CallArgs...>
162 operator()(_CallArgs&&... __call_args) &&
163 noexcept(_S_noexcept_invocable<_Binder&&, _CallArgs...>())
164 {
165 return _S_call(std::move(*this),
166 std::forward<_CallArgs>(__call_args)...);
167 }
168
169 template<typename... _CallArgs>
170 requires true
171 constexpr _Result_t<const _Binder&&, _CallArgs...>
172 operator()(_CallArgs&&... __call_args) const &&
173 noexcept(_S_noexcept_invocable<const _Binder&&, _CallArgs...>())
174 {
175 return _S_call(std::move(*this),
176 std::forward<_CallArgs>(__call_args)...);
177 }
178
179 template<typename... _CallArgs>
180 void operator()(_CallArgs&&...) & = delete;
181
182 template<typename... _CallArgs>
183 void operator()(_CallArgs&&...) const & = delete;
184
185 template<typename... _CallArgs>
186 void operator()(_CallArgs&&...) && = delete;
187
188 template<typename... _CallArgs>
189 void operator()(_CallArgs&&...) const && = delete;
190#endif
191
192 template<typename _Tp, typename... _CallArgs>
193 static constexpr
194 decltype(auto)
195 _S_call(_Tp&& __g, _CallArgs&&... __call_args)
196 {
197 if constexpr (sizeof...(_BoundArgs) > 1)
198 return _BoundArgsStorage::template _S_apply<_Back>(
199 std::forward<_Tp>(__g)._M_fd,
200 std::forward<_Tp>(__g)._M_bound_args,
201 std::forward<_CallArgs>(__call_args)...);
202 else if constexpr (sizeof...(_BoundArgs) == 0)
203 return std::__invoke(std::forward<_Tp>(__g)._M_fd,
204 std::forward<_CallArgs>(__call_args)...);
205 else if constexpr (_Back) // sizeof...(_BoundArgs) == 1
206 return std::__invoke(std::forward<_Tp>(__g)._M_fd,
207 std::forward<_CallArgs>(__call_args)...,
208 std::forward<_Tp>(__g)._M_bound_args);
209 else // !_Back && sizeof...(_BoundArgs) == 1
210 return std::__invoke(std::forward<_Tp>(__g)._M_fd,
211 std::forward<_Tp>(__g)._M_bound_args,
212 std::forward<_CallArgs>(__call_args)...);
213 }
214
215 private:
216 using _BoundArgsStorage
217 // _BoundArgs are required to be move-constructible, so this is valid.
218 = decltype(__make_bound_args<_BoundArgs...>(std::declval<_BoundArgs>()...));
219
220 [[no_unique_address]] _Fd _M_fd;
221 [[no_unique_address]] _BoundArgsStorage _M_bound_args;
222 };
223
224 template<typename _Fn, typename... _Args>
225 using _Bind_front_t = _Binder<false, decay_t<_Fn>, decay_t<_Args>...>;
226
227 // for zero bounds args behavior of bind_front and bind_back is the same,
228 // so reuse _Bind_front_t, i.e. _Binder<false, ...>
229 template<typename _Fn, typename... _Args>
230 using _Bind_back_t
231 = _Binder<(sizeof...(_Args) > 0), decay_t<_Fn>, decay_t<_Args>...>;
232
233_GLIBCXX_END_NAMESPACE_VERSION
234} // namespace std
235
236#endif // __cplusplus >= 202002L
237#endif // _GLIBCXX_BINDERS_H
invoke.h
move.h
std::decay_t
typename decay< _Tp >::type decay_t
Alias template for decay.
Definition type_traits:2963
std::declval
auto declval() noexcept -> decltype(__declval< _Tp >(0))
Definition type_traits:2741
std::move
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
std::__invoke
constexpr __invoke_result< _Callable, _Args... >::type __invoke(_Callable &&__fn, _Args &&... __args) noexcept(__is_nothrow_invocable< _Callable, _Args... >::value)
Invoke a callable object.
Definition invoke.h:92
std::forward
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
std
ISO C++ entities toplevel namespace is std.
std::index_sequence
integer_sequence< size_t, _Idx... > index_sequence
Alias template index_sequence.
Definition utility.h:555
std::index_sequence_for
make_index_sequence< sizeof...(_Types)> index_sequence_for
Alias template index_sequence_for.
Definition utility.h:563