summaryrefslogtreecommitdiff
path: root/indra/llcommon/apply.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/apply.h')
-rw-r--r--indra/llcommon/apply.h68
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