14
14
15
15
#pragma once
16
16
17
- #include < concepts>
18
-
19
- #include " subspace/mem/forward.h"
17
+ #include " subspace/fn/__private/signature.h"
20
18
#include " subspace/mem/move.h"
21
19
22
20
namespace sus ::fn {
23
21
22
+ // / When used as the return type of the function signature in `Fn`, `FnMut` and
23
+ // / `FnOnce`, the concepts will match against any return type from a functor
24
+ // / except `void`.
24
25
struct NonVoid {
25
26
template <class T >
26
27
constexpr NonVoid (T&&) noexcept {}
27
28
};
28
29
30
+ // / When used as the return type of the function signature in `Fn`, `FnMut` and
31
+ // / `FnOnce`, the concepts will match against any return type from a functor
32
+ // / including `void`.
29
33
struct Anything {
30
34
template <class T >
31
35
constexpr Anything (T&&) noexcept {}
32
36
};
33
37
34
- namespace __private {
35
- template <class ... Ts>
36
- struct Pack ;
37
-
38
- template <class R , class ... Args>
39
- struct Sig ;
40
-
41
- template <class R , class ... A>
42
- struct Sig <R(A...)> {
43
- using Return = R;
44
- using Args = Pack<A...>;
45
- };
46
-
47
- struct NoOverloadMatchesArguments {};
48
-
49
- template <class F , class ArgsPack >
50
- struct InvokedFnOnce {
51
- constexpr static NoOverloadMatchesArguments return_type ();
52
- };
53
-
54
- template <class F , class ... Ts>
55
- requires requires (F&& f) {
56
- { ::sus::move (f)(std::declval<Ts>()...) };
57
- }
58
- struct InvokedFnOnce <F, Pack<Ts...>> {
59
- constexpr static decltype (std::declval<F&&>()(std::declval<Ts>()...))
60
- return_type();
61
- };
62
-
63
- template <class F , class ArgsPack >
64
- struct InvokedFnMut {
65
- constexpr static NoOverloadMatchesArguments return_type ();
66
- };
67
-
68
- template <class F , class ... Ts>
69
- requires requires (F& f) {
70
- { f (std::declval<Ts>()...) };
71
- }
72
- struct InvokedFnMut <F, Pack<Ts...>> {
73
- constexpr static decltype (std::declval<F&>()(std::declval<Ts>()...))
74
- return_type();
75
- };
76
-
77
- template <class F , class ArgsPack >
78
- struct InvokedFn {
79
- constexpr static NoOverloadMatchesArguments return_type ();
80
- };
81
-
82
- template <class F , class ... Ts>
83
- requires requires (const F& f) {
84
- { f (std::declval<Ts>()...) };
85
- }
86
- struct InvokedFn <F, Pack<Ts...>> {
87
- constexpr static decltype (std::declval<const F&>()(std::declval<Ts>()...))
88
- return_type();
89
- };
90
-
91
- template <class ReturnType , class T >
92
- concept ValidReturnType =
93
- !std::same_as<ReturnType, NoOverloadMatchesArguments> &&
94
- (std::same_as<::sus::fn::Anything, T> ||
95
- std::convertible_to<ReturnType, T>);
96
- } // namespace __private
97
-
98
38
// / The version of a callable object that is called on an rvalue (moved-from)
99
39
// / receiver. A `FnOnce` is typically the best fit for any callable that will
100
40
// / only be called at most once. However when a template (or constexpr) is not
@@ -116,6 +56,8 @@ concept ValidReturnType =
116
56
// / ```
117
57
// /
118
58
// / # Use of `FnOnce`
59
+ // / The `sus::run_once()` helper ensures that FnOnce is called correctly.
60
+ // /
119
61
// / A `FnOnce` should only be called once, and should be moved with
120
62
// / `sus::move()` when calling it. It is typically received as an rvalue
121
63
// / reference to avoid an unnecessary copy or move operation.
@@ -153,11 +95,14 @@ concept ValidReturnType =
153
95
// / });
154
96
// / sus::check(x == 400 + 4);
155
97
// / ```
156
- template <class F , class S >
98
+ template <class F , class ... S>
157
99
concept FnOnce = requires (F&& f) {
100
+ // Receives and passes along the signature as a pack instead of a single
101
+ // argument in order to consistently provide a static_assert() in `Sig` when
102
+ // `S` is not a function signature.
158
103
{
159
- __private::InvokedFnOnce<F, typename __private::Sig<S>::Args>::return_type ()
160
- } -> __private::ValidReturnType<typename __private::Sig<S>::Return>;
104
+ __private::InvokedFnOnce<F, typename __private::Sig<S... >::Args>::returns ()
105
+ } -> __private::ValidReturnType<typename __private::Sig<S... >::Return>;
161
106
};
162
107
163
108
// / The version of a callable object that is allowed to mutate internal state
@@ -185,6 +130,8 @@ concept FnOnce = requires(F&& f) {
185
130
// / ```
186
131
// /
187
132
// / # Use of `FnMut`
133
+ // / The `sus::run_mut()` helper ensures that `FnMut` is called correctly.
134
+ // /
188
135
// / A `FnMut` may be called any number of times, unlike `FnOnce`, and need not
189
136
// / be moved when called. It is typically received as a function parameter by
190
137
// / value, which isolates any internal mutation to the current function.
@@ -219,13 +166,16 @@ concept FnOnce = requires(F&& f) {
219
166
// / });
220
167
// / sus::check(x == 401 + 102);
221
168
// / ```
222
- template <class F , class S >
169
+ template <class F , class ... S>
223
170
concept FnMut = requires (F& f) {
171
+ // Receives and passes along the signature as a pack instead of a single
172
+ // argument in order to consistently provide a static_assert() in `Sig` when
173
+ // `S` is not a function signature.
224
174
{
225
- __private::InvokedFnMut<F, typename __private::Sig<S>::Args>::return_type ()
226
- } -> __private::ValidReturnType<typename __private::Sig<S>::Return>;
175
+ __private::InvokedFnMut<F, typename __private::Sig<S... >::Args>::returns ()
176
+ } -> __private::ValidReturnType<typename __private::Sig<S... >::Return>;
227
177
228
- requires FnOnce<F, S>;
178
+ requires FnOnce<F, S... >;
229
179
};
230
180
231
181
// / The version of a callable object that may be called multiple times without
@@ -253,6 +203,8 @@ concept FnMut = requires(F& f) {
253
203
// / ```
254
204
// /
255
205
// / # Use of `Fn`
206
+ // / The `sus::run()` helper ensures that `Fn` is called correctly.
207
+ // /
256
208
// / A `Fn` may be called any number of times, unlike `FnOnce`, and need not
257
209
// / be moved when called. It is typically received as a function parameter as a
258
210
// / const reference, which ensures a non-mutating call operator will be used.
@@ -286,14 +238,17 @@ concept FnMut = requires(F& f) {
286
238
// / });
287
239
// / sus::check(x == 401 + 101);
288
240
// / ```
289
- template <class F , class S >
241
+ template <class F , class ... S>
290
242
concept Fn = requires (const F& f) {
243
+ // Receives and passes along the signature as a pack instead of a single
244
+ // argument in order to consistently provide a static_assert() in `Sig` when
245
+ // `S` is not a function signature.
291
246
{
292
- __private::InvokedFn<F, typename __private::Sig<S>::Args>::return_type ()
293
- } -> __private::ValidReturnType<typename __private::Sig<S>::Return>;
247
+ __private::InvokedFn<F, typename __private::Sig<S... >::Args>::returns ()
248
+ } -> __private::ValidReturnType<typename __private::Sig<S... >::Return>;
294
249
295
- requires FnMut<F, S>;
296
- requires FnOnce<F, S>;
250
+ requires FnMut<F, S... >;
251
+ requires FnOnce<F, S... >;
297
252
};
298
253
299
254
} // namespace sus::fn
0 commit comments