Last active
August 5, 2022 10:26
-
-
Save AltimorTASDK/63208b3f7d1c7a7da7941b3bb8205ae3 to your computer and use it in GitHub Desktop.
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 <algorithm> | |
#include <type_traits> | |
#include <utility> | |
using std::size_t; | |
template<typename Target> | |
class field_list { | |
template<size_t N> | |
struct reader { | |
friend constexpr auto query(reader<N>); | |
}; | |
template<size_t N, typename T> | |
struct writer { | |
friend constexpr auto query(reader<N>) { return std::type_identity<T>{}; } | |
}; | |
public: | |
struct nop { | |
using target = Target; | |
template<size_t N, typename T> | |
struct writer {}; | |
template<size_t N, typename T> | |
static constexpr auto set() { return writer<N, T>{}; } | |
}; | |
using target = Target; | |
template<size_t N = 0, auto = []{}> | |
static constexpr auto size() | |
{ | |
if constexpr (requires { query(reader<N>{}); }) | |
return size<N + 1>(); | |
else | |
return N; | |
} | |
template<size_t N> | |
using get = typename decltype(query(reader<N>{}))::type; | |
template<size_t N, typename T> | |
static constexpr auto set() { return writer<N, T>{}; } | |
}; | |
template<size_t N> | |
struct dummy_probe { | |
template<typename T> constexpr operator T&() const&& noexcept; | |
template<typename T> constexpr operator T&&() const&& noexcept; | |
}; | |
template<typename List, size_t N> | |
struct prvalue_probe { | |
template<typename T> | |
constexpr operator T() const&& noexcept((List::template set<N, T>(), true)); | |
}; | |
template<typename List, size_t N> | |
struct lvalue_probe { | |
template<typename T> | |
constexpr operator T&() const&& noexcept((List::template set<N, T&>(), true)); | |
}; | |
template<typename List, size_t N> | |
struct xvalue_probe { | |
template<typename T> | |
constexpr operator T&&() const&& noexcept((List::template set<N, T&&>(), true)); | |
}; | |
template<typename Target, size_t N> | |
constexpr auto struct_size_check = []<size_t ...I>(std::index_sequence<I...>) { | |
return requires { Target { std::declval<dummy_probe<I>>()... }; }; | |
}(std::make_index_sequence<N>()); | |
template<typename Target, size_t N = 0> requires requires { | |
requires struct_size_check<Target, N>; | |
requires !struct_size_check<Target, N+1>; | |
} constexpr auto struct_size() { return N; } | |
template<typename Target, size_t N = 0> | |
constexpr auto struct_size() { return struct_size<Target, N+1>(); } | |
template<typename List, size_t N, template<typename, size_t> typename Probe> | |
constexpr auto probe_field_check() | |
{ | |
using target = typename List::target; | |
constexpr auto remaining_fields = std::max(struct_size<target>(), N + 1) - N - 1; | |
return []<size_t ...I, size_t ...J>(std::index_sequence<I...>, std::index_sequence<J...>) { | |
return requires { | |
target { dummy_probe<I>{}..., Probe<List, N>{}, dummy_probe<J>{}... }; | |
}; | |
}(std::make_index_sequence<N>(), std::make_index_sequence<remaining_fields>()); | |
} | |
template<typename List, size_t N> requires requires { | |
requires probe_field_check<typename List::nop, N, lvalue_probe>(); | |
requires !probe_field_check<typename List::nop, N, prvalue_probe>(); | |
} constexpr void probe_field_impl() noexcept(probe_field_check<List, N, lvalue_probe>()) {} | |
template<typename List, size_t N> requires requires { | |
requires probe_field_check<typename List::nop, N, prvalue_probe>(); | |
requires probe_field_check<typename List::nop, N, lvalue_probe>(); | |
} constexpr void probe_field_impl() noexcept(probe_field_check<List, N, prvalue_probe>()) {} | |
template<typename List, size_t N> requires requires { | |
requires probe_field_check<typename List::nop, N, xvalue_probe>(); | |
requires !probe_field_check<typename List::nop, N, lvalue_probe>(); | |
} constexpr void probe_field_impl() noexcept(probe_field_check<List, N, xvalue_probe>()) {} | |
template<typename Target> | |
constexpr void probe_fields() | |
{ | |
[]<size_t ...I>(std::index_sequence<I...>) { | |
(probe_field_impl<field_list<Target>, I>(), ...); | |
}(std::make_index_sequence<struct_size<Target>()>()); | |
} | |
int main() | |
{ | |
struct S { | |
int my; | |
int &super; | |
int &&laser; | |
float piss; | |
}; | |
static_assert(struct_size<S>() == 4); | |
probe_fields<S>(); | |
static_assert(std::is_same_v<field_list<S>::get<0>, int>); | |
static_assert(std::is_same_v<field_list<S>::get<1>, int&>); | |
static_assert(std::is_same_v<field_list<S>::get<2>, int&&>); | |
static_assert(std::is_same_v<field_list<S>::get<3>, float>); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment