Skip to content

Instantly share code, notes, and snippets.

@niXman
Last active November 18, 2022 09:41
Show Gist options
  • Save niXman/64223c7e033f44dbaafe173d94b55703 to your computer and use it in GitHub Desktop.
Save niXman/64223c7e033f44dbaafe173d94b55703 to your computer and use it in GitHub Desktop.
struct to tuple
#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