Last active
November 18, 2022 09:41
-
-
Save niXman/64223c7e033f44dbaafe173d94b55703 to your computer and use it in GitHub Desktop.
struct to tuple
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <tuple> | |
#include <type_traits> | |
struct any_type { template<class T> constexpr operator T(); }; | |
#if defined(__GNUC__) && !defined(__clang__) | |
# pragma GCC diagnostic push | |
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" | |
#elif defined(__clang__) | |
# pragma clang diagnostic push | |
# pragma clang diagnostic ignored "-Wmissing-field-initializers" | |
#endif | |
template<class T, std::size_t... I> | |
decltype(void(T{(I, std::declval<any_type>())...}), std::true_type{}) | |
test_is_braces_constructible_n(std::index_sequence<I...>); | |
#if defined(__GNUC__) && !defined(__clang__) | |
# pragma GCC diagnostic pop | |
#elif defined(__clang__) | |
# pragma clang diagnostic pop | |
#endif | |
template <class, class...> | |
std::false_type test_is_braces_constructible_n(...); | |
template <class T, std::size_t N> | |
using is_braces_constructible_n = | |
decltype(test_is_braces_constructible_n<T>(std::make_index_sequence<N>{})); | |
template<class T, std::size_t L = 0u, std::size_t R = sizeof(T) + 1u> | |
constexpr std::size_t to_tuple_size_impl() { | |
constexpr std::size_t M = (L + R) / 2u; | |
return (M == 0) | |
? std::is_empty<T>{} | |
? 0u | |
: throw "Unable to determine number of elements" | |
: (L == M) | |
? M | |
: is_braces_constructible_n<T, M>{} | |
? to_tuple_size_impl<T, M, R>() | |
: to_tuple_size_impl<T, L, M>() | |
; | |
} | |
template<class T> | |
using to_tuple_size = std::integral_constant<std::size_t, to_tuple_size_impl<T>()>; | |
#ifndef __JUSTARGS_TO_TUPLE_MAX | |
#define __JUSTARGS_TO_TUPLE_MAX 20 | |
#endif | |
template<class T> | |
auto to_tuple_impl(T&&, std::integral_constant<std::size_t, 0>) noexcept { | |
return std::make_tuple(); | |
} | |
#define __JUSTARGS_CAT_IMPL(l, r) l##r | |
#define __JUSTARGS_CAT(l, r) __JUSTARGS_CAT_IMPL(l, r) | |
#define __JUSTARGS_REPEAT_0(macro, data) | |
#define __JUSTARGS_REPEAT_1(macro, data) \ | |
macro(0, data) | |
#define __JUSTARGS_REPEAT_2(macro, data) \ | |
__JUSTARGS_REPEAT_1(macro, data) macro(1, data) | |
#define __JUSTARGS_REPEAT_3(macro, data) \ | |
__JUSTARGS_REPEAT_2(macro, data) macro(2, data) | |
#define __JUSTARGS_REPEAT_4(macro, data) \ | |
__JUSTARGS_REPEAT_3(macro, data) macro(3, data) | |
#define __JUSTARGS_REPEAT_5(macro, data) \ | |
__JUSTARGS_REPEAT_4(macro, data) macro(4, data) | |
#define __JUSTARGS_REPEAT_6(macro, data) \ | |
__JUSTARGS_REPEAT_5(macro, data) macro(5, data) | |
#define __JUSTARGS_REPEAT_7(macro, data) \ | |
__JUSTARGS_REPEAT_6(macro, data) macro(6, data) | |
#define __JUSTARGS_REPEAT_8(macro, data) \ | |
__JUSTARGS_REPEAT_7(macro, data) macro(7, data) | |
#define __JUSTARGS_REPEAT_9(macro, data) \ | |
__JUSTARGS_REPEAT_8(macro, data) macro(8, data) | |
#define __JUSTARGS_REPEAT_10(macro, data) \ | |
__JUSTARGS_REPEAT_9(macro, data) macro(9, data) | |
#define __JUSTARGS_REPEAT_11(macro, data) \ | |
__JUSTARGS_REPEAT_10(macro, data) macro(10, data) | |
#define __JUSTARGS_REPEAT_12(macro, data) \ | |
__JUSTARGS_REPEAT_11(macro, data) macro(11, data) | |
#define __JUSTARGS_REPEAT_13(macro, data) \ | |
__JUSTARGS_REPEAT_12(macro, data) macro(12, data) | |
#define __JUSTARGS_REPEAT_14(macro, data) \ | |
__JUSTARGS_REPEAT_13(macro, data) macro(13, data) | |
#define __JUSTARGS_REPEAT_15(macro, data) \ | |
__JUSTARGS_REPEAT_14(macro, data) macro(14, data) | |
#define __JUSTARGS_REPEAT_16(macro, data) \ | |
__JUSTARGS_REPEAT_15(macro, data) macro(15, data) | |
#define __JUSTARGS_REPEAT_17(macro, data) \ | |
__JUSTARGS_REPEAT_16(macro, data) macro(16, data) | |
#define __JUSTARGS_REPEAT_18(macro, data) \ | |
__JUSTARGS_REPEAT_17(macro, data) macro(17, data) | |
#define __JUSTARGS_REPEAT_19(macro, data) \ | |
__JUSTARGS_REPEAT_18(macro, data) macro(18, data) | |
#define __JUSTARGS_REPEAT_20(macro, data) \ | |
__JUSTARGS_REPEAT_19(macro, data) macro(19, data) | |
#define __JUSTARGS_REPEAT_IMPL(start_macro, macro, data) \ | |
start_macro(macro, data) | |
#define __JUSTARGS_REPEAT(n, macro, data) \ | |
__JUSTARGS_REPEAT_IMPL(__JUSTARGS_CAT(__JUSTARGS_REPEAT_, n), macro, data) | |
#define __JUSTARGS_TO_TUPLE_P(idx, data) , p##idx | |
#define __JUSTARGS_TO_TUPLE_SPECIALIZATION(idx, data) \ | |
template<class T> \ | |
auto to_tuple_impl(T&& object, std::integral_constant<std::size_t, idx + 1>) noexcept { \ | |
auto&& [p __JUSTARGS_REPEAT_##idx(__JUSTARGS_TO_TUPLE_P, data)] = object; \ | |
return std::make_tuple(p __JUSTARGS_REPEAT_##idx(__JUSTARGS_TO_TUPLE_P, data)); \ | |
} | |
__JUSTARGS_REPEAT(__JUSTARGS_TO_TUPLE_MAX, __JUSTARGS_TO_TUPLE_SPECIALIZATION, ~) | |
#undef __JUSTARGS_TO_TUPLE_SPECIALIZATION | |
#undef __JUSTARGS_TO_TUPLE_P | |
template< | |
class T | |
,class = struct current_value | |
,std::size_t = __JUSTARGS_TO_TUPLE_MAX | |
,class = struct required_value | |
,std::size_t N | |
> | |
auto to_tuple_impl(T&&, std::integral_constant<std::size_t, N>) noexcept { | |
static_assert(N <= __JUSTARGS_TO_TUPLE_MAX, "Please increase TO_TUPLE_MAX"); | |
} | |
template< | |
class T | |
,class = std::enable_if_t<std::is_class<T>::value && std::is_standard_layout<T>::value> | |
> | |
auto to_tuple(T&& object) noexcept { | |
return to_tuple_impl(std::forward<T>(object), to_tuple_size<std::decay_t<T>>{}); | |
} | |
/************************************************************************************************************/ | |
#include <iostream> | |
#include <cassert> | |
int main() { | |
{ | |
struct s { | |
int p1; | |
double p2; | |
}; | |
auto t = to_tuple(s{1, 2.0}); | |
static_assert(std::is_same<std::tuple<int, double>, decltype(t)>{}, ""); | |
assert(1 == std::get<0>(t)); | |
assert(2.0 == std::get<1>(t)); | |
} | |
{ | |
struct s { | |
struct nested { } p1; | |
int p2; | |
int p3; | |
s* p4; | |
}; | |
auto t = to_tuple(s{s::nested{}, 42, 87, nullptr}); | |
static_assert(std::is_same<std::tuple<s::nested, int, int, s*>, decltype(t)>{}, ""); | |
assert(42 == std::get<1>(t)); | |
assert(87 == std::get<2>(t)); | |
assert(nullptr == std::get<3>(t)); | |
} | |
} | |
/************************************************************************************************************/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment