25#ifndef FBCPP_STRUCT_BINDING_H
26#define FBCPP_STRUCT_BINDING_H
42 concept Aggregate = std::is_aggregate_v<T> && !std::is_array_v<T> && !std::is_union_v<T>;
51namespace fbcpp::impl::reflection
54 inline constexpr std::size_t maxFieldCount = 32;
58 struct IsOptional : std::false_type
63 struct IsOptional<std::optional<T>> : std::true_type
68 inline constexpr bool isOptionalV = IsOptional<T>::value;
74 struct IsVariant : std::false_type
78 template <
typename... Ts>
79 struct IsVariant<std::variant<Ts...>> : std::true_type
84 inline constexpr bool isVariantV = IsVariant<T>::value;
89 template <
typename T,
typename Variant>
90 struct VariantContains : std::false_type
94 template <
typename T,
typename... Ts>
95 struct VariantContains<T, std::variant<Ts...>> : std::disjunction<std::is_same<T, Ts>...>
99 template <
typename T,
typename Variant>
100 inline constexpr bool variantContainsV = VariantContains<T, Variant>::value;
106 template <
typename T>
107 struct IsOpaqueType : std::false_type
111 template <
typename T>
112 inline constexpr bool isOpaqueTypeV = IsOpaqueType<T>::value;
117 template <
typename T>
118 constexpr operator T() const noexcept
120 if constexpr (isOptionalV<T>)
121 return T{std::nullopt};
128 template <
typename T,
typename Seq,
typename =
void>
129 struct IsBraceConstructibleImpl : std::false_type
133#if defined(__GNUC__) && !defined(__clang__)
134#pragma GCC diagnostic push
135#pragma GCC diagnostic ignored "-Wconversion"
138 template <
typename T, std::size_t... Is>
139 struct IsBraceConstructibleImpl<T, std::index_sequence<Is...>,
140 std::void_t<decltype(T{(void(Is), UniversalType{})...})>> : std::true_type
144#if defined(__GNUC__) && !defined(__clang__)
145#pragma GCC diagnostic pop
148 template <
typename T, std::
size_t N>
149 inline constexpr bool isBraceConstructibleV = IsBraceConstructibleImpl<T, std::make_index_sequence<N>>::value;
152 template <
typename T, std::
size_t Lo, std::
size_t Hi>
153 constexpr std::size_t detectFieldCount()
155 if constexpr (Lo == Hi)
159 constexpr std::size_t Mid = Lo + (Hi - Lo + 1) / 2;
160 if constexpr (isBraceConstructibleV<T, Mid>)
161 return detectFieldCount<T, Mid, Hi>();
163 return detectFieldCount<T, Lo, Mid - 1>();
168 template <
typename T>
169 inline constexpr std::size_t fieldCountV = detectFieldCount<T, 0, maxFieldCount>();
172 template <
typename T>
173 auto toTupleRef(T&& obj)
175 constexpr std::size_t N = fieldCountV<std::remove_cvref_t<T>>;
177 if constexpr (N == 0)
178 return std::tuple<>{};
179 else if constexpr (N == 1)
181 auto&& [v1] = std::forward<T>(obj);
182 return std::forward_as_tuple(v1);
184 else if constexpr (N == 2)
186 auto&& [v1, v2] = std::forward<T>(obj);
187 return std::forward_as_tuple(v1, v2);
189 else if constexpr (N == 3)
191 auto&& [v1, v2, v3] = std::forward<T>(obj);
192 return std::forward_as_tuple(v1, v2, v3);
194 else if constexpr (N == 4)
196 auto&& [v1, v2, v3, v4] = std::forward<T>(obj);
197 return std::forward_as_tuple(v1, v2, v3, v4);
199 else if constexpr (N == 5)
201 auto&& [v1, v2, v3, v4, v5] = std::forward<T>(obj);
202 return std::forward_as_tuple(v1, v2, v3, v4, v5);
204 else if constexpr (N == 6)
206 auto&& [v1, v2, v3, v4, v5, v6] = std::forward<T>(obj);
207 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6);
209 else if constexpr (N == 7)
211 auto&& [v1, v2, v3, v4, v5, v6, v7] = std::forward<T>(obj);
212 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7);
214 else if constexpr (N == 8)
216 auto&& [v1, v2, v3, v4, v5, v6, v7, v8] = std::forward<T>(obj);
217 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8);
219 else if constexpr (N == 9)
221 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9] = std::forward<T>(obj);
222 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9);
224 else if constexpr (N == 10)
226 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] = std::forward<T>(obj);
227 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
229 else if constexpr (N == 11)
231 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11] = std::forward<T>(obj);
232 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
234 else if constexpr (N == 12)
236 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12] = std::forward<T>(obj);
237 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
239 else if constexpr (N == 13)
241 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13] = std::forward<T>(obj);
242 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
244 else if constexpr (N == 14)
246 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14] = std::forward<T>(obj);
247 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14);
249 else if constexpr (N == 15)
251 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = std::forward<T>(obj);
252 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
254 else if constexpr (N == 16)
256 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16] = std::forward<T>(obj);
257 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16);
259 else if constexpr (N == 17)
261 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17] = std::forward<T>(obj);
262 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17);
264 else if constexpr (N == 18)
266 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18] =
267 std::forward<T>(obj);
268 return std::forward_as_tuple(
269 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18);
271 else if constexpr (N == 19)
273 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19] =
274 std::forward<T>(obj);
275 return std::forward_as_tuple(
276 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
278 else if constexpr (N == 20)
280 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20] =
281 std::forward<T>(obj);
282 return std::forward_as_tuple(
283 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
285 else if constexpr (N == 21)
287 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21] =
288 std::forward<T>(obj);
289 return std::forward_as_tuple(
290 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
292 else if constexpr (N == 22)
294 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
295 v22] = std::forward<T>(obj);
296 return std::forward_as_tuple(
297 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22);
299 else if constexpr (N == 23)
301 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
302 v23] = std::forward<T>(obj);
303 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
304 v18, v19, v20, v21, v22, v23);
306 else if constexpr (N == 24)
308 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
309 v23, v24] = std::forward<T>(obj);
310 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
311 v18, v19, v20, v21, v22, v23, v24);
313 else if constexpr (N == 25)
315 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
316 v23, v24, v25] = std::forward<T>(obj);
317 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
318 v18, v19, v20, v21, v22, v23, v24, v25);
320 else if constexpr (N == 26)
322 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
323 v23, v24, v25, v26] = std::forward<T>(obj);
324 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
325 v18, v19, v20, v21, v22, v23, v24, v25, v26);
327 else if constexpr (N == 27)
329 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
330 v23, v24, v25, v26, v27] = std::forward<T>(obj);
331 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
332 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
334 else if constexpr (N == 28)
336 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
337 v23, v24, v25, v26, v27, v28] = std::forward<T>(obj);
338 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
339 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28);
341 else if constexpr (N == 29)
343 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
344 v23, v24, v25, v26, v27, v28, v29] = std::forward<T>(obj);
345 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
346 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29);
348 else if constexpr (N == 30)
350 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
351 v23, v24, v25, v26, v27, v28, v29, v30] = std::forward<T>(obj);
352 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
353 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30);
355 else if constexpr (N == 31)
357 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
358 v23, v24, v25, v26, v27, v28, v29, v30, v31] = std::forward<T>(obj);
359 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
360 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31);
362 else if constexpr (N == 32)
364 auto&& [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
365 v23, v24, v25, v26, v27, v28, v29, v30, v31, v32] = std::forward<T>(obj);
366 return std::forward_as_tuple(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
367 v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32);
370 static_assert(N <= maxFieldCount,
"Struct has too many fields for struct binding (max 32)");
374 template <
typename T>
375 using TupleType =
decltype(toTupleRef(std::declval<T&>()));
378 template <
typename T, std::
size_t I>
379 using FieldType = std::remove_reference_t<std::tuple_element_t<I, TupleType<T>>>;
387 template <
typename T>
388 concept VariantLike = impl::reflection::isVariantV<std::remove_cvref_t<T>>;
Concept constraining types to aggregates suitable for struct binding.
Concept constraining types to tuple-like types (std::tuple, std::pair, std::array).
Concept constraining types to std::variant types.