@@ -32,10 +32,68 @@ struct Anything {
32
32
};
33
33
34
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
+
35
91
template <class ReturnType , class T >
36
- concept CorrectReturn =
37
- std::same_as<::sus::fn::Anything, T> || std::convertible_to<ReturnType, T>;
38
- }
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
39
97
40
98
// / The version of a callable object that is called on an rvalue (moved-from)
41
99
// / receiver. A `FnOnce` is typically the best fit for any callable that will
@@ -49,6 +107,14 @@ concept CorrectReturn =
49
107
// / is not `&`-qualified). Mutable and const lambdas will satisfy
50
108
// / `FnOnce`.
51
109
// /
110
+ // / The second argument of `FnOnce<F, S>` is a function signature with the
111
+ // / format `ReturnType(Args...)`, where `Args...` are the arguments that will
112
+ // / be passed to the `FnOnce` and `ReturnType` is what is expected to be
113
+ // / received back. It would appear as a matching concept as:
114
+ // / ```
115
+ // / void function(FnOnce<ReturnType(Args...)> auto&& f) { ... }
116
+ // / ```
117
+ // /
52
118
// / # Use of `FnOnce`
53
119
// / A `FnOnce` should only be called once, and should be moved with
54
120
// / `sus::move()` when calling it. It is typically received as an rvalue
@@ -78,7 +144,7 @@ concept CorrectReturn =
78
144
// / ```
79
145
// / // Accepts any type that can be called once with (Option<i32>) and returns
80
146
// / // i32.
81
- // / i32 call_once(sus::fn::FnOnce<i32, sus::Option<i32>> auto&& f) {
147
+ // / i32 call_once(sus::fn::FnOnce<i32( sus::Option<i32>) > auto&& f) {
82
148
// / return sus::move(f)(sus::some(400)); // Returns an i32.
83
149
// / }
84
150
// /
@@ -87,11 +153,11 @@ concept CorrectReturn =
87
153
// / });
88
154
// / sus::check(x == 400 + 4);
89
155
// / ```
90
- template <class F , class R , class ... Args >
91
- concept FnOnce = requires (F&& f, Args... args ) {
156
+ template <class F , class S >
157
+ concept FnOnce = requires (F&& f) {
92
158
{
93
- ::sus::move (f)(::sus::forward< Args>(args)... )
94
- } -> __private::CorrectReturn<R >;
159
+ __private::InvokedFnOnce<F, typename __private::Sig<S>:: Args>:: return_type ( )
160
+ } -> __private::ValidReturnType< typename __private::Sig<S>::Return >;
95
161
};
96
162
97
163
// / The version of a callable object that is allowed to mutate internal state
@@ -110,6 +176,14 @@ concept FnOnce = requires(F&& f, Args... args) {
110
176
// / is not `&&`-qualified). Mutable and const lambdas will satisfy
111
177
// / `FnMut`.
112
178
// /
179
+ // / The second argument of `FnMut<F, S>` is a function signature with the
180
+ // / format `ReturnType(Args...)`, where `Args...` are the arguments that will
181
+ // / be passed to the `FnMut` and `ReturnType` is what is expected to be
182
+ // / received back. It would appear as a matching concept as:
183
+ // / ```
184
+ // / void function(FnMut<ReturnType(Args...)> auto f) { ... }
185
+ // / ```
186
+ // /
113
187
// / # Use of `FnMut`
114
188
// / A `FnMut` may be called any number of times, unlike `FnOnce`, and need not
115
189
// / be moved when called. It is typically received as a function parameter by
@@ -135,7 +209,7 @@ concept FnOnce = requires(F&& f, Args... args) {
135
209
// / ```
136
210
// / // Accepts any type that can be called once with (Option<i32>) and returns
137
211
// / // i32.
138
- // / static i32 call_mut(sus::fn::FnMut<i32, sus::Option<i32>> auto f) {
212
+ // / static i32 call_mut(sus::fn::FnMut<i32( sus::Option<i32>) > auto f) {
139
213
// / return f(sus::some(400)) + f(sus::some(100)); // Returns an i32.
140
214
// / }
141
215
// /
@@ -145,10 +219,13 @@ concept FnOnce = requires(F&& f, Args... args) {
145
219
// / });
146
220
// / sus::check(x == 401 + 102);
147
221
// / ```
148
- template <class F , class R , class ... Args>
149
- concept FnMut = requires (F& f, Args... args) {
150
- { f (::sus::forward<Args>(args)...) } -> __private::CorrectReturn<R>;
151
- requires FnOnce<F, R, Args...>;
222
+ template <class F , class S >
223
+ concept FnMut = requires (F& f) {
224
+ {
225
+ __private::InvokedFnMut<F, typename __private::Sig<S>::Args>::return_type ()
226
+ } -> __private::ValidReturnType<typename __private::Sig<S>::Return>;
227
+
228
+ requires FnOnce<F, S>;
152
229
};
153
230
154
231
// / The version of a callable object that may be called multiple times without
@@ -167,6 +244,14 @@ concept FnMut = requires(F& f, Args... args) {
167
244
// / is not `&&`-qualified). Mutable and const lambdas will satisfy
168
245
// / `FnMut`.
169
246
// /
247
+ // / The second argument of `Fn<F, S>` is a function signature with the format
248
+ // / `ReturnType(Args...)`, where `Args...` are the arguments that will be passed
249
+ // / to the `Fn` and `ReturnType` is what is expected to be received back. It
250
+ // / would appear as a matching concept as:
251
+ // / ```
252
+ // / void function(const Fn<ReturnType(Args...)> auto& f) { ... }
253
+ // / ```
254
+ // /
170
255
// / # Use of `Fn`
171
256
// / A `Fn` may be called any number of times, unlike `FnOnce`, and need not
172
257
// / be moved when called. It is typically received as a function parameter as a
@@ -192,20 +277,23 @@ concept FnMut = requires(F& f, Args... args) {
192
277
// / ```
193
278
// / // Accepts any type that can be called once with (Option<i32>) and returns
194
279
// / // i32.
195
- // / static i32 call_fn(const sus::fn::Fn<i32, sus::Option<i32>> auto& f) {
280
+ // / static i32 call_fn(const sus::fn::Fn<i32( sus::Option<i32>) > auto& f) {
196
281
// / return f(sus::some(400)) + f(sus::some(100)); // Returns an i32.
197
282
// / }
198
- // /
283
+ // /
199
284
// / i32 x = call_fn([i = 1_i32](sus::Option<i32> o) -> i32 {
200
285
// / return sus::move(o).unwrap_or_default() + i;
201
286
// / });
202
287
// / sus::check(x == 401 + 101);
203
288
// / ```
204
- template <class F , class R , class ... Args>
205
- concept Fn = requires (const F& f, Args... args) {
206
- { f (::sus::forward<Args>(args)...) } -> __private::CorrectReturn<R>;
207
- requires FnMut<F, R, Args...>;
208
- requires FnOnce<F, R, Args...>;
289
+ template <class F , class S >
290
+ concept Fn = requires (const F& f) {
291
+ {
292
+ __private::InvokedFn<F, typename __private::Sig<S>::Args>::return_type ()
293
+ } -> __private::ValidReturnType<typename __private::Sig<S>::Return>;
294
+
295
+ requires FnMut<F, S>;
296
+ requires FnOnce<F, S>;
209
297
};
210
298
211
299
} // namespace sus::fn
0 commit comments