1313
1414#include < Framework/Traits.h>
1515#include < array>
16+ #include < tuple>
1617
1718// Structured binding packs (P1061) are C++26, but clang implements them as an
1819// extension in every language mode and advertises them via the feature test
@@ -91,11 +92,13 @@ consteval int homogeneous_apply_refs_size()
9192#pragma clang diagnostic push
9293#pragma clang diagnostic ignored "-Wc++26-extensions"
9394#endif
94- template <bool B = false , class T , int D = 0 , typename L>
95+ template <bool B = false , class T , int D = 0 , typename L, bool Cat = false >
9596constexpr auto homogeneous_apply_refs (L l, T&& object)
9697{
9798 auto && [... members] = object;
98- if constexpr (sizeof ...(members) == 0 ) {
99+ if constexpr (Cat) {
100+ return std::tuple_cat (l (members)...);
101+ } else if constexpr (sizeof ...(members) == 0 ) {
99102 return std::array<bool , 0 >();
100103 } else {
101104 return std::array{l (members)...};
@@ -155,28 +158,42 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
155158
156159#define DPL_FENUM (f, pre, post, d, u ) DPL_FENUM_ ##d##0 (f, pre , post ), DPL_FENUM_ ##u(f, pre ##d, post )
157160
158- #define DPL_HOMOGENEOUS_APPLY_ENTRY_LOW ( u ) \
159- constexpr (numElements == u) \
160- { \
161- auto && [ DPL_ENUM_ ## u (p, )] = object; \
162- return std::array<decltype (l (p0)), u>{ DPL_FENUM_ ## u (l, p, ) }; \
161+ #define DPL_HOMOGENEOUS_APPLY_RESULT (n, ...) \
162+ if constexpr (Cat) { \
163+ return std::tuple_cat (__VA_ARGS__); \
164+ } else { \
165+ return std::array<decltype (l (p0)), n>{__VA_ARGS__ }; \
163166 }
164167
165- #define DPL_HOMOGENEOUS_APPLY_ENTRY ( d, u ) \
166- constexpr (numElements == d##u) \
167- { \
168- auto && [ DPL_ENUM (p, , d, u)] = object; \
169- return std::array<decltype ( l (p0)), d##u>{ DPL_FENUM (l, p, , d, u)}; \
168+ #define DPL_HOMOGENEOUS_APPLY_EMPTY \
169+ if constexpr (Cat) { \
170+ return std::tuple<>(); \
171+ } else { \
172+ return std::array<bool , 0 >(); \
170173 }
171174
172- #define DPL_HOMOGENEOUS_APPLY_ENTRY_TENS ( d ) \
173- constexpr (numElements == d## 0 ) \
174- { \
175- auto && [DPL_ENUM_ ##d## 0 (p, )] = object; \
176- return std::array< decltype ( l (p0)), d## 0 >{ DPL_FENUM_ ##d## 0 (l, p, )}; \
175+ #define DPL_HOMOGENEOUS_APPLY_ENTRY_LOW ( u ) \
176+ constexpr (numElements == u) \
177+ { \
178+ auto && [DPL_ENUM_ ##u (p, )] = object; \
179+ DPL_HOMOGENEOUS_APPLY_RESULT (u, DPL_FENUM_ ##u (l, p, )) \
177180 }
178181
179- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
182+ #define DPL_HOMOGENEOUS_APPLY_ENTRY (d, u ) \
183+ constexpr (numElements == d##u) \
184+ { \
185+ auto && [DPL_ENUM (p, , d, u)] = object; \
186+ DPL_HOMOGENEOUS_APPLY_RESULT (d##u, DPL_FENUM (l, p, , d, u)) \
187+ }
188+
189+ #define DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (d ) \
190+ constexpr (numElements == d##0 ) \
191+ { \
192+ auto && [DPL_ENUM_ ##d##0 (p, )] = object; \
193+ DPL_HOMOGENEOUS_APPLY_RESULT (d##0 , DPL_FENUM_ ##d##0 (l, p, )) \
194+ }
195+
196+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
180197 requires (D == 9 )
181198constexpr auto homogeneous_apply_refs(L l, T&& object)
182199{
@@ -192,11 +209,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
192209 else if DPL_HOMOGENEOUS_APPLY_ENTRY (9 , 2 )
193210 else if DPL_HOMOGENEOUS_APPLY_ENTRY (9 , 1 )
194211 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (9 )
195- else { return std::array< bool , 0 >(); }
212+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
196213 // clang-format on
197214}
198215
199- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
216+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
200217 requires (D == 8 )
201218constexpr auto homogeneous_apply_refs(L l, T&& object)
202219{
@@ -212,11 +229,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
212229 else if DPL_HOMOGENEOUS_APPLY_ENTRY (8 , 2 )
213230 else if DPL_HOMOGENEOUS_APPLY_ENTRY (8 , 1 )
214231 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (8 )
215- else { return std::array< bool , 0 >(); }
232+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
216233 // clang-format on
217234}
218235
219- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
236+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
220237 requires (D == 7 )
221238constexpr auto homogeneous_apply_refs(L l, T&& object)
222239{
@@ -232,11 +249,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
232249 else if DPL_HOMOGENEOUS_APPLY_ENTRY (7 , 2 )
233250 else if DPL_HOMOGENEOUS_APPLY_ENTRY (7 , 1 )
234251 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (7 )
235- else { return std::array< bool , 0 >(); }
252+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
236253 // clang-format on
237254}
238255
239- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
256+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
240257 requires (D == 6 )
241258constexpr auto homogeneous_apply_refs(L l, T&& object)
242259{
@@ -252,11 +269,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
252269 else if DPL_HOMOGENEOUS_APPLY_ENTRY (6 , 2 )
253270 else if DPL_HOMOGENEOUS_APPLY_ENTRY (6 , 1 )
254271 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (6 )
255- else { return std::array< bool , 0 >(); }
272+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
256273 // clang-format on
257274}
258275
259- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
276+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
260277 requires (D == 5 )
261278constexpr auto homogeneous_apply_refs(L l, T&& object)
262279{
@@ -272,11 +289,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
272289 else if DPL_HOMOGENEOUS_APPLY_ENTRY (5 , 2 )
273290 else if DPL_HOMOGENEOUS_APPLY_ENTRY (5 , 1 )
274291 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (5 )
275- else { return std::array< bool , 0 >(); }
292+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
276293 // clang-format on
277294}
278295
279- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
296+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
280297 requires (D == 4 )
281298constexpr auto homogeneous_apply_refs(L l, T&& object)
282299{
@@ -292,11 +309,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
292309 else if DPL_HOMOGENEOUS_APPLY_ENTRY (4 , 2 )
293310 else if DPL_HOMOGENEOUS_APPLY_ENTRY (4 , 1 )
294311 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (4 )
295- else { return std::array< bool , 0 >(); }
312+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
296313 // clang-format on
297314}
298315
299- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
316+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
300317 requires (D == 3 )
301318constexpr auto homogeneous_apply_refs(L l, T&& object)
302319{
@@ -312,11 +329,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
312329 else if DPL_HOMOGENEOUS_APPLY_ENTRY (3 , 2 )
313330 else if DPL_HOMOGENEOUS_APPLY_ENTRY (3 , 1 )
314331 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (3 )
315- else { return std::array< bool , 0 >(); }
332+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
316333 // clang-format on
317334}
318335
319- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
336+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
320337 requires (D == 2 )
321338constexpr auto homogeneous_apply_refs(L l, T&& object)
322339{
@@ -332,11 +349,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
332349 else if DPL_HOMOGENEOUS_APPLY_ENTRY (2 , 2 )
333350 else if DPL_HOMOGENEOUS_APPLY_ENTRY (2 , 1 )
334351 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (2 )
335- else { return std::array< bool , 0 >(); }
352+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
336353 // clang-format on
337354}
338355
339- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
356+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
340357 requires (D == 1 )
341358constexpr auto homogeneous_apply_refs(L l, T&& object)
342359{
@@ -352,11 +369,11 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
352369 else if DPL_HOMOGENEOUS_APPLY_ENTRY (1 , 2 )
353370 else if DPL_HOMOGENEOUS_APPLY_ENTRY (1 , 1 )
354371 else if DPL_HOMOGENEOUS_APPLY_ENTRY_TENS (1 )
355- else { return std::array< bool , 0 >(); }
372+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
356373 // clang-format on
357374}
358375
359- template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L>
376+ template <bool B = false , class T , int D = nested_brace_constructible_size<B, T>() / 10 , typename L, bool Cat = false >
360377 requires (D == 0 )
361378constexpr auto homogeneous_apply_refs(L l, T&& object)
362379{
@@ -371,7 +388,7 @@ constexpr auto homogeneous_apply_refs(L l, T&& object)
371388 else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (3 )
372389 else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (2 )
373390 else if DPL_HOMOGENEOUS_APPLY_ENTRY_LOW (1 )
374- else { return std::array< bool , 0 >(); }
391+ else { DPL_HOMOGENEOUS_APPLY_EMPTY }
375392 // clang-format on
376393}
377394
@@ -383,6 +400,15 @@ constexpr auto homogeneous_apply_refs_sized(L l, T&& object)
383400 return homogeneous_apply_refs<false , T, D, L>(l, object);
384401}
385402
403+ // / Like homogeneous_apply_refs_sized, but l returns a std::tuple for each
404+ // / member and the results are concatenated: returning std::tuple<M&> or
405+ // / std::tuple<>() selects members. The calls to l are unsequenced.
406+ template <int D, typename T, typename L>
407+ constexpr auto apply_refs_tuple_cat_sized (L l, T&& object)
408+ {
409+ return homogeneous_apply_refs<false , T, D, L, true >(l, object);
410+ }
411+
386412} // namespace o2::framework
387413
388414#endif // O2_FRAMEWORK_STRUCTTOTUPLE_H_
0 commit comments