diff options
Diffstat (limited to 'indra/llcommon/apply.h')
-rw-r--r-- | indra/llcommon/apply.h | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index ef4a8fd68b..7c58d63bc0 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -12,11 +12,48 @@ #if ! defined(LL_APPLY_H) #define LL_APPLY_H +#include <boost/type_traits/function_traits.hpp> #include <tuple> namespace LL { +/** + * USAGE NOTE: + * https://stackoverflow.com/a/40523474/5533635 + * + * If you're trying to pass apply() a variadic function, the compiler + * complains that it can't deduce the callable type, presumably because it + * doesn't know which arity to reify to pass. + * + * But it works to wrap the variadic function in a generic lambda, e.g.: + * + * @CODE + * LL::apply( + * [](auto&&... args) + * { + * return variadic(std::forward<decltype(args)>(args)...); + * }, + * args); + * @ENDCODE + * + * Presumably this is because there's only one instance of the generic lambda + * @em type, with a variadic <tt>operator()()</tt>. + * + * It's pointless to provide a wrapper @em function that implicitly supplies + * the generic lambda. You couldn't pass your variadic function to our wrapper + * function, for the same original reason! + * + * Instead we provide a wrapper @em macro. Sorry, Dr. Stroustrup. + */ +#define VAPPLY(FUNC, ARGS) \ + LL::apply( \ + [](auto&&... args) \ + { \ + return (FUNC)(std::forward<decltype(args)>(args)...); \ + }, \ + (ARGS)) + #if __cplusplus >= 201703L // C++17 implementation @@ -34,16 +71,43 @@ auto apply_impl(CALLABLE&& func, TUPLE&& args, std::index_sequence<I...>) } template <typename CALLABLE, typename... ARGS> -auto apply(CALLABLE&& func, std::tuple<ARGS...>&& args) +auto apply(CALLABLE&& func, const std::tuple<ARGS...>& args) { // std::index_sequence_for is the magic sauce here, generating an argument // pack of indexes for each entry in args. apply_impl() can then pass // those to std::get() to unpack args into individual arguments. return apply_impl(std::forward<CALLABLE>(func), - std::forward<std::tuple<ARGS...>>(args), + args, std::index_sequence_for<ARGS...>{}); } +// per https://stackoverflow.com/a/57510428/5533635 +template <typename CALLABLE, typename T, size_t SIZE> +auto apply(CALLABLE&& func, const std::array<T, SIZE>& args) +{ + return apply(std::forward<CALLABLE>(func), std::tuple_cat(args)); +} + +// per https://stackoverflow.com/a/28411055/5533635 +template <typename CALLABLE, typename T, std::size_t... I> +auto apply_impl(CALLABLE&& func, const std::vector<T>& args, std::index_sequence<I...>) +{ + return apply_impl(std::forward<CALLABLE>(func), + std::make_tuple(std::forward<T>(args[I])...), + I...); +} + +// this goes beyond C++17 std::apply() +template <typename CALLABLE, typename T> +auto apply(CALLABLE&& func, const std::vector<T>& args) +{ + constexpr auto arity = boost::function_traits<CALLABLE>::arity; + assert(args.size() == arity); + return apply_impl(std::forward<CALLABLE>(func), + args, + std::make_index_sequence<arity>()); +} + #endif // C++14 } // namespace LL |