Created
August 10, 2024 03:00
-
-
Save fredemmott/d33f6db63da0309ac72a933b0a524294 to your computer and use it in GitHub Desktop.
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
| template <size_t... I> | |
| struct drop_last_impl_t { | |
| drop_last_impl_t() = delete; | |
| constexpr drop_last_impl_t(std::index_sequence<I...>) { | |
| } | |
| template <template <class...> class T, class... TArgs> | |
| using next_t = T<std::tuple_element_t<I, std::tuple<TArgs...>>...>; | |
| template <class TIn> | |
| static constexpr decltype(auto) make_tuple(TIn&& in) { | |
| return std::forward_as_tuple( | |
| std::forward<std::tuple_element_t<I, TIn>>(get<I>(in))...); | |
| } | |
| }; | |
| template <class... TArgs> | |
| struct drop_last_t { | |
| using seq_t = std::make_index_sequence<sizeof...(TArgs) - 1>; | |
| using impl_t = decltype(drop_last_impl_t(seq_t {})); | |
| template <template <class...> class T> | |
| using next_t = impl_t::template next_t<T, TArgs...>; | |
| template <class... TInitArgs> | |
| static constexpr decltype(auto) make_tuple(TInitArgs&&... args) { | |
| return impl_t::make_tuple( | |
| std::forward_as_tuple(std::forward<TInitArgs>(args)...)); | |
| } | |
| }; | |
| template <class TFn, class... TArgs> | |
| struct arg_dropping_invocable_t { | |
| static consteval bool value_fn() { | |
| if constexpr (std::invocable<TFn, TArgs...>) { | |
| return true; | |
| } else if constexpr (sizeof...(TArgs) >= 1) { | |
| using next_t | |
| = drop_last_t<TFn, TArgs...>::template next_t<arg_dropping_invocable_t>; | |
| return next_t::value_fn(); | |
| } | |
| return false; | |
| } | |
| static constexpr bool value = value_fn(); | |
| }; | |
| template <class TFn, class... TArgs> | |
| concept arg_dropping_invocable = arg_dropping_invocable_t<TFn, TArgs...>::value; | |
| template <class TFn, class... TArgs> | |
| requires arg_dropping_invocable<TFn, TArgs...> | |
| struct arg_dropping_invoker_t { | |
| static constexpr auto invoke(TFn&& fn, TArgs&&... args) { | |
| if constexpr (std::invocable<TFn, TArgs...>) { | |
| return std::invoke(std::forward<TFn>(fn), std::forward<TArgs>(args)...); | |
| } else if constexpr (sizeof...(TArgs) >= 1) { | |
| using dropper_t = drop_last_t<TFn, TArgs...>; | |
| using next_t | |
| = drop_last_t<TFn, TArgs...>::template next_t<arg_dropping_invoker_t>; | |
| auto next_args = dropper_t::make_tuple( | |
| std::forward<TFn>(fn), std::forward<TArgs>(args)...); | |
| return std::apply( | |
| []<class... NextArgs>(NextArgs&&... args) { | |
| return next_t::invoke(std::forward<NextArgs>(args)...); | |
| }, | |
| std::move(next_args)); | |
| } else { | |
| static_assert(false, "Should be statically unreachable due to concept"); | |
| } | |
| } | |
| }; | |
| template <class TFn, class... TArgs> | |
| constexpr auto arg_dropping_invoke(TFn&& fn, TArgs&&... args) { | |
| return arg_dropping_invoker_t<TFn, TArgs...>::invoke( | |
| std::forward<TFn>(fn), std::forward<TArgs>(args)...); | |
| } | |
| constexpr auto test_fn = [](int a, int b) { return a + b; }; | |
| static_assert(arg_dropping_invocable<decltype(test_fn), int, int>); | |
| static_assert(arg_dropping_invocable<decltype(test_fn), int, int, int>); | |
| static_assert(arg_dropping_invocable<decltype(test_fn), int, int, void*>); | |
| static_assert(arg_dropping_invocable<decltype(test_fn), int, int, float*>); | |
| static_assert(!arg_dropping_invocable<decltype(test_fn), int>); | |
| static_assert(!arg_dropping_invocable<decltype(test_fn), int, float*>); | |
| static_assert(arg_dropping_invoke(test_fn, 1, 2) == 3); | |
| static_assert(arg_dropping_invoke(test_fn, 1, 2, 3) == 3); | |
| static_assert(arg_dropping_invoke(test_fn, 1, 2, "i am not an int") == 3); | |
| static_assert(arg_dropping_invoke(test_fn, 1, 2, nullptr) == 3); | |
| static_assert(arg_dropping_invoke(test_fn, 1, 2, nullptr, "lolwhut") == 3); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment