14
14
#include " internal/nth_element_t.hpp"
15
15
#include " internal/variant/find_max_size.hpp"
16
16
#include " internal/variant/is_alternative_type.hpp"
17
+ #include " internal/variant/result_t.hpp"
17
18
18
19
namespace rfl {
19
20
@@ -24,8 +25,6 @@ class Variant {
24
25
25
26
static constexpr unsigned long num_bytes_ = max_size_wrapper_.size_;
26
27
27
- using LargestType = typename decltype (max_size_wrapper_)::Type;
28
-
29
28
using DataType = std::array<unsigned char , num_bytes_>;
30
29
31
30
using IndexType =
@@ -35,8 +34,11 @@ class Variant {
35
34
36
35
static constexpr IndexType size_ = sizeof ...(AlternativeTypes);
37
36
37
+ template <class F >
38
+ using result_t = internal::variant::result_t <F, AlternativeTypes...>;
39
+
38
40
template <IndexType _i>
39
- struct Index {} ;
41
+ using Index = std::integral_constant<IndexType, _i> ;
40
42
41
43
public:
42
44
Variant () {
@@ -146,14 +148,17 @@ class Variant {
146
148
}
147
149
148
150
template <class F >
149
- auto visit (F& _f) {
150
- using FirstAlternative = internal::nth_element_t <0 , AlternativeTypes...>;
151
- using ResultType = std::remove_cvref_t <
152
- std::invoke_result_t <std::remove_cvref_t <F>, FirstAlternative&>>;
151
+ result_t <F> visit (F& _f) {
152
+ using ResultType = result_t <F>;
153
153
if constexpr (std::is_same_v<ResultType, void >) {
154
154
bool visited = false ;
155
155
do_visit_no_result (_f, &visited,
156
156
std::make_integer_sequence<IndexType, size_>());
157
+ } else if constexpr (std::is_reference_v<ResultType>) {
158
+ std::remove_reference_t <ResultType>* res = nullptr ;
159
+ do_visit_with_reference (_f, &res,
160
+ std::make_integer_sequence<IndexType, size_>());
161
+ return *res;
157
162
} else {
158
163
auto res = std::optional<ResultType>();
159
164
do_visit_with_result (_f, &res,
@@ -163,14 +168,17 @@ class Variant {
163
168
}
164
169
165
170
template <class F >
166
- auto visit (F& _f) const {
167
- using FirstAlternative = internal::nth_element_t <0 , AlternativeTypes...>;
168
- using ResultType = std::remove_cvref_t <
169
- std::invoke_result_t <std::remove_cvref_t <F>, FirstAlternative&>>;
171
+ result_t <F> visit (F& _f) const {
172
+ using ResultType = result_t <F>;
170
173
if constexpr (std::is_same_v<ResultType, void >) {
171
174
bool visited = false ;
172
175
do_visit_no_result (_f, &visited,
173
176
std::make_integer_sequence<IndexType, size_>());
177
+ } else if constexpr (std::is_reference_v<ResultType>) {
178
+ std::remove_reference_t <ResultType>* res = nullptr ;
179
+ do_visit_with_reference (_f, &res,
180
+ std::make_integer_sequence<IndexType, size_>());
181
+ return *res;
174
182
} else {
175
183
auto res = std::optional<ResultType>();
176
184
do_visit_with_result (_f, &res,
@@ -180,14 +188,17 @@ class Variant {
180
188
}
181
189
182
190
template <class F >
183
- auto visit (const F& _f) {
184
- using FirstAlternative = internal::nth_element_t <0 , AlternativeTypes...>;
185
- using ResultType = std::remove_cvref_t <
186
- std::invoke_result_t <std::remove_cvref_t <F>, FirstAlternative&>>;
191
+ result_t <F> visit (const F& _f) {
192
+ using ResultType = std::remove_reference_t <result_t <F>>;
187
193
if constexpr (std::is_same_v<ResultType, void >) {
188
194
bool visited = false ;
189
195
do_visit_no_result (_f, &visited,
190
196
std::make_integer_sequence<IndexType, size_>());
197
+ } else if constexpr (std::is_reference_v<ResultType>) {
198
+ std::remove_reference_t <ResultType>* res = nullptr ;
199
+ do_visit_with_reference (_f, &res,
200
+ std::make_integer_sequence<IndexType, size_>());
201
+ return *res;
191
202
} else {
192
203
auto res = std::optional<ResultType>();
193
204
do_visit_with_result (_f, &res,
@@ -197,14 +208,17 @@ class Variant {
197
208
}
198
209
199
210
template <class F >
200
- auto visit (const F& _f) const {
201
- using FirstAlternative = internal::nth_element_t <0 , AlternativeTypes...>;
202
- using ResultType = std::remove_cvref_t <
203
- std::invoke_result_t <std::remove_cvref_t <F>, FirstAlternative&>>;
211
+ result_t <F> visit (const F& _f) const {
212
+ using ResultType = result_t <F>;
204
213
if constexpr (std::is_same_v<ResultType, void >) {
205
214
bool visited = false ;
206
215
do_visit_no_result (_f, &visited,
207
216
std::make_integer_sequence<IndexType, size_>());
217
+ } else if constexpr (std::is_reference_v<ResultType>) {
218
+ std::remove_reference_t <ResultType>* res = nullptr ;
219
+ do_visit_with_reference (_f, &res,
220
+ std::make_integer_sequence<IndexType, size_>());
221
+ return *res;
208
222
} else {
209
223
auto res = std::optional<ResultType>();
210
224
do_visit_with_result (_f, &res,
@@ -264,32 +278,6 @@ class Variant {
264
278
(visit_one (_f, _visited, Index<_is>{}), ...);
265
279
}
266
280
267
- template <class F , class ResultType , IndexType... _is>
268
- void do_visit_with_result (F& _f, std::optional<ResultType>* _res,
269
- std::integer_sequence<IndexType, _is...>) {
270
- auto visit_one = [this ]<IndexType _i>(const F& _f,
271
- std::optional<ResultType>* _res,
272
- Index<_i>) {
273
- if (!*_res && index_ == _i) {
274
- *_res = _f (get_alternative<_i>());
275
- }
276
- };
277
- (visit_one (_f, _res, Index<_is>{}), ...);
278
- }
279
-
280
- template <class F , class ResultType , IndexType... _is>
281
- void do_visit_with_result (F& _f, std::optional<ResultType>* _res,
282
- std::integer_sequence<IndexType, _is...>) const {
283
- auto visit_one = [this ]<IndexType _i>(const F& _f,
284
- std::optional<ResultType>* _res,
285
- Index<_i>) {
286
- if (!*_res && index_ == _i) {
287
- *_res = _f (get_alternative<_i>());
288
- }
289
- };
290
- (visit_one (_f, _res, Index<_is>{}), ...);
291
- }
292
-
293
281
template <class F , IndexType... _is>
294
282
void do_visit_no_result (const F& _f, bool * _visited,
295
283
std::integer_sequence<IndexType, _is...>) {
@@ -316,6 +304,32 @@ class Variant {
316
304
(visit_one (_f, _visited, Index<_is>{}), ...);
317
305
}
318
306
307
+ template <class F , class ResultType , IndexType... _is>
308
+ void do_visit_with_result (F& _f, std::optional<ResultType>* _res,
309
+ std::integer_sequence<IndexType, _is...>) {
310
+ auto visit_one = [this ]<IndexType _i>(const F& _f,
311
+ std::optional<ResultType>* _res,
312
+ Index<_i>) {
313
+ if (!*_res && index_ == _i) {
314
+ *_res = _f (get_alternative<_i>());
315
+ }
316
+ };
317
+ (visit_one (_f, _res, Index<_is>{}), ...);
318
+ }
319
+
320
+ template <class F , class ResultType , IndexType... _is>
321
+ void do_visit_with_result (F& _f, std::optional<ResultType>* _res,
322
+ std::integer_sequence<IndexType, _is...>) const {
323
+ auto visit_one = [this ]<IndexType _i>(const F& _f,
324
+ std::optional<ResultType>* _res,
325
+ Index<_i>) {
326
+ if (!*_res && index_ == _i) {
327
+ *_res = _f (get_alternative<_i>());
328
+ }
329
+ };
330
+ (visit_one (_f, _res, Index<_is>{}), ...);
331
+ }
332
+
319
333
template <class F , class ResultType , IndexType... _is>
320
334
void do_visit_with_result (const F& _f, std::optional<ResultType>* _res,
321
335
std::integer_sequence<IndexType, _is...>) {
@@ -342,6 +356,54 @@ class Variant {
342
356
(visit_one (_f, _res, Index<_is>{}), ...);
343
357
}
344
358
359
+ template <class F , class ResultType , IndexType... _is>
360
+ void do_visit_with_reference (F& _f, ResultType** _res,
361
+ std::integer_sequence<IndexType, _is...>) {
362
+ const auto visit_one = [this ]<IndexType _i>(const F& _f, ResultType** _res,
363
+ Index<_i>) {
364
+ if (!*_res && index_ == _i) {
365
+ *_res = &_f (get_alternative<_i>());
366
+ }
367
+ };
368
+ (visit_one (_f, _res, Index<_is>{}), ...);
369
+ }
370
+
371
+ template <class F , class ResultType , IndexType... _is>
372
+ void do_visit_with_reference (F& _f, ResultType** _res,
373
+ std::integer_sequence<IndexType, _is...>) const {
374
+ const auto visit_one = [this ]<IndexType _i>(const F& _f, ResultType** _res,
375
+ Index<_i>) {
376
+ if (!*_res && index_ == _i) {
377
+ *_res = &_f (get_alternative<_i>());
378
+ }
379
+ };
380
+ (visit_one (_f, _res, Index<_is>{}), ...);
381
+ }
382
+
383
+ template <class F , class ResultType , IndexType... _is>
384
+ void do_visit_with_reference (const F& _f, ResultType** _res,
385
+ std::integer_sequence<IndexType, _is...>) {
386
+ const auto visit_one = [this ]<IndexType _i>(const F& _f, ResultType** _res,
387
+ Index<_i>) {
388
+ if (!*_res && index_ == _i) {
389
+ *_res = &_f (get_alternative<_i>());
390
+ }
391
+ };
392
+ (visit_one (_f, _res, Index<_is>{}), ...);
393
+ }
394
+
395
+ template <class F , class ResultType , IndexType... _is>
396
+ void do_visit_with_reference (const F& _f, ResultType** _res,
397
+ std::integer_sequence<IndexType, _is...>) const {
398
+ const auto visit_one = [this ]<IndexType _i>(const F& _f, ResultType** _res,
399
+ Index<_i>) {
400
+ if (!*_res && index_ == _i) {
401
+ *_res = &_f (get_alternative<_i>());
402
+ }
403
+ };
404
+ (visit_one (_f, _res, Index<_is>{}), ...);
405
+ }
406
+
345
407
template <IndexType _i>
346
408
auto & get_alternative () noexcept {
347
409
using CurrentType = internal::nth_element_t <_i, AlternativeTypes...>;
@@ -376,7 +438,7 @@ class Variant {
376
438
IndexType index_;
377
439
378
440
// / The underlying data, can be any of the underlying types.
379
- alignas (LargestType ) DataType data_;
441
+ alignas (AlternativeTypes... ) DataType data_;
380
442
};
381
443
382
444
template <class T , class ... Types>
0 commit comments