Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <type_traits>
- template <class T, std::size_t N>
- struct tag {
- friend auto loophole(tag<T,N>);
- };
- template <class T> constexpr T& unsafe_declval_like() noexcept {
- return *std::add_pointer_t<T>{nullptr};
- }
- template <class T, class U, std::size_t N, bool B>
- struct fn_def {
- friend auto loophole(tag<T,N>) {
- return ::unsafe_declval_like< std::remove_all_extents_t<U> >(); }
- };
- template <class T, class U, std::size_t N>
- struct fn_def<T, U, N, true> {};
- template <class T, std::size_t N>
- struct loophole_ubiq {
- template<class U, std::size_t M>
- static std::size_t ins(...);
- template<class U, std::size_t M, std::size_t = sizeof(loophole(tag<T,M>{})) >
- static char ins(int);
- template<class U, std::size_t =
- sizeof(fn_def<T, U, N, sizeof(ins<U, N>(0)) == sizeof(char)>)>
- constexpr operator U&() const noexcept;
- };
- /*****************************/
- struct ubiq
- {
- template <class T>
- constexpr operator T() const noexcept { return {}; }
- };
- template <typename T>
- struct Type {};
- template <class S, typename... l>
- struct next_type
- {
- using type = void;
- };
- template <class S, typename... l>
- requires requires { S{ std::declval<l>()..., ubiq{} }; }
- struct next_type<S,l...>
- {
- template <std::size_t N>
- struct loophole_type
- : Type< decltype( S{ std::declval<l>()..., loophole_ubiq<S,N>{} }, 0) >
- {
- using type = decltype(loophole(tag<S,N>{}));
- };
- // the next member type, or for array member the element type
- using type = typename loophole_type<sizeof...(l)>::type;
- template <typename T=type>
- static constexpr bool init_1_brace = requires { S{ std::declval<l>()..., {std::declval<T>()} }; };
- static constexpr bool is_array = init_1_brace<type> && !std::is_aggregate_v<type>;
- };
- template <class S, typename... L>
- using next_type_t = typename next_type<S,L...>::type;
- struct A { int a[1]; };
- struct B { int a; };
- struct C { B b; };
- struct D : B {};
- struct E : A {};
- struct F { int h[1][2]; };
- static_assert(std::is_same_v< next_type_t<A>, int> && next_type<A>::is_array);
- static_assert(std::is_same_v< next_type_t<B>, int> && !next_type<B>::is_array);
- static_assert(std::is_same_v< next_type_t<C>, B> && !next_type<C>::is_array);
- static_assert(std::is_same_v< next_type_t<D>, B> && !next_type<D>::is_array);
- static_assert(std::is_same_v< next_type_t<E>, A> && !next_type<E>::is_array);
- static_assert(std::is_same_v< next_type_t<F>, int> && next_type<F>::is_array);
- static_assert(std::is_same_v< next_type_t<A,int>, void>);
- int main() { }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement