Last active
October 6, 2020 19:32
-
-
Save notfoundry/fe1385de99133048d552e543d81db719 to your computer and use it in GitHub Desktop.
Universal type-level `apply` metafunction
This file contains hidden or 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 <type_traits | |
| #include "meta_invoke.hpp" | |
| #define ASSERT_SAME(...) static_assert(std::is_same_v<__VA_ARGS__>) | |
| struct f1 { | |
| template <class T> | |
| using f = T*; | |
| }; | |
| ASSERT_SAME(META_INVOKE((f1), int), int*); | |
| template <class T> | |
| using f2 = T*; | |
| ASSERT_SAME(META_INVOKE((f2), int), int*); | |
| template <auto X> | |
| using f3 = decltype(X); | |
| ASSERT_SAME(META_INVOKE((f3), 1), int); | |
| struct f4 { | |
| template <auto X> | |
| using f = decltype(X); | |
| }; | |
| ASSERT_SAME(META_INVOKE((f4), 1), int); | |
| struct f5 { | |
| template <auto X> | |
| constexpr static auto f = X; | |
| }; | |
| static_assert(META_INVOKE((f5), 1) == 1); | |
| constexpr auto f6 = []<auto X>() -> decltype(X) {}; | |
| ASSERT_SAME(META_INVOKE((f6), 1), int); |
This file contains hidden or 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 <experimental/type_traits> | |
| namespace detail { | |
| template <class... Fs> struct overload : Fs... { using Fs::operator()...; }; | |
| template <class... Fs> overload(Fs...) -> overload<Fs...>; | |
| template <class T> struct type_ { using dependant = T; }; | |
| template <auto X> struct value_ { constexpr static auto dependant = X; }; | |
| template <bool> | |
| struct dcallf_class { | |
| template <template <class...> class F1, class... Ts> | |
| using f = F1<Ts...>; | |
| }; | |
| template <> | |
| struct dcallf_class<false> { | |
| template <template <class...> class F1, class... Ts> | |
| using f = F1<>; | |
| }; | |
| template <bool> | |
| struct dcallf_auto { | |
| template <template <auto...> class F1, auto... Ts> | |
| using f = F1<Ts...>; | |
| }; | |
| template <> | |
| struct dcallf_auto<false> { | |
| template <template <auto...> class F1, auto... Ts> | |
| using f = F1<>; | |
| }; | |
| template <template <class...> class F> | |
| struct lift_tmetafunction { | |
| template <class... Ts> | |
| using f = type_<typename dcallf_class<(sizeof...(Ts) > 0)>::template f<F, Ts...>>; | |
| }; | |
| template <template <auto...> class F> | |
| struct lift_vmetafunction { | |
| template <auto... Ts> | |
| using f = type_<typename dcallf_auto<(sizeof...(Ts) > 0)>::template f<F, Ts...>>; | |
| }; | |
| template <auto TypeF, auto ValueF> | |
| struct dispatch_type_or_value { | |
| template <class F> | |
| using try_instantiate_typef = decltype(TypeF.template operator()<F>()); | |
| template <class F> | |
| using try_instantiate_valuef = decltype(ValueF.template operator()<F>()); | |
| template <class F> | |
| static auto f() { | |
| if constexpr (std::experimental::is_detected<try_instantiate_typef, F>::value) { | |
| return type_<decltype(TypeF.template operator()<F>())>(); | |
| } else if (std::experimental::is_detected<try_instantiate_valuef, F>::value) { | |
| return value_<ValueF.template operator()<F>()>(); | |
| } else { | |
| throw; | |
| } | |
| } | |
| }; | |
| } | |
| #define META_INVOKE_EAT_PARENS(...) __VA_ARGS__ | |
| #define META_INVOKE(fn, ...) \ | |
| decltype(detail::overload( \ | |
| []<class F>() -> decltype(detail::dispatch_type_or_value< \ | |
| []<class G>() -> typename G::template f<__VA_ARGS__> { throw; }, \ | |
| []<class G>(){ return G::template f<__VA_ARGS__>; } \ | |
| >::template f<F>()) { throw; }, \ | |
| []<template <class...> class F>() -> typename detail::lift_tmetafunction<F>::template f<__VA_ARGS__> { throw; }, \ | |
| []<template <auto...> class F>() -> typename detail::lift_vmetafunction<F>::template f<__VA_ARGS__> { throw; }, \ | |
| []<auto F>() -> detail::type_<decltype(F.template operator()<__VA_ARGS__>())> { throw; } \ | |
| ).template operator()<META_INVOKE_EAT_PARENS fn>())::dependant |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment