<div dir="ltr">Given a tuple of type Ts..., invokes a user-supplied functor passing Ts... variadically as the parameter list, allowing the functor to return a new tuple (of a<span class="inbox-inbox-Apple-converted-space"> </span>possibly different type).<div><br></div><div>I believe this is standard in C++17, so I'm adding it early.  In one of the test cases I demonstrate some useful use cases, including that of iterating efficiently iterating and de-referencing multiple ranges in parallel.</div><div><br></div><div><div>From 46117057cdbd3558cb542a3fd6969b0dcde304ab Mon Sep 17 00:00:00 2001</div><div>From: Zachary Turner <<a href="mailto:zturner@google.com">zturner@google.com</a>></div><div>Date: Thu, 29 Sep 2016 15:16:35 -0700</div><div>Subject: [PATCH] apply_tuple</div><div><br></div><div>---</div><div> include/llvm/ADT/STLExtras.h    | 13 +++++++++</div><div> unittests/ADT/STLExtrasTest.cpp | 63 +++++++++++++++++++++++++++++++++++++++++</div><div> 2 files changed, 76 insertions(+)</div><div><br></div><div>diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h</div><div>index 63f919d..5ebba37 100644</div><div>--- a/include/llvm/ADT/STLExtras.h</div><div>+++ b/include/llvm/ADT/STLExtras.h</div><div>@@ -24,6 +24,7 @@</div><div> #include <functional></div><div> #include <iterator></div><div> #include <memory></div><div>+#include <tuple></div><div> #include <utility> // for std::pair</div><div><br></div><div> #include "llvm/ADT/Optional.h"</div><div>@@ -680,6 +681,18 @@ template <typename R> auto enumerate(R &&Range) {</div><div>   return detail::enumerator_impl<I, V>(std::begin(Range), std::end(Range));</div><div> }</div><div><br></div><div>+template <typename F, typename Tuple, std::size_t... I></div><div>+auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence<I...>) {</div><div>+  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);</div><div>+}</div><div>+</div><div>+template <typename F, typename Tuple> auto apply_tuple(F &&f, Tuple &&t) {</div><div>+  using Indices =</div><div>+      build_index_impl<std::tuple_size<std::decay<Tuple>::type>::value>;</div><div>+</div><div>+  return apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),</div><div>+                          Indices());</div><div>+}</div><div> } // End llvm namespace</div><div><br></div><div> #endif</div><div>diff --git a/unittests/ADT/STLExtrasTest.cpp b/unittests/ADT/STLExtrasTest.cpp</div><div>index d7457f5..26953cb 100644</div><div>--- a/unittests/ADT/STLExtrasTest.cpp</div><div>+++ b/unittests/ADT/STLExtrasTest.cpp</div><div>@@ -79,4 +79,67 @@ TEST(STLExtrasTest, EnumerateModify) {</div><div>   EXPECT_EQ('c', foo[1]);</div><div>   EXPECT_EQ('d', foo[2]);</div><div> }</div><div>+</div><div>+TEST(STLExtrasTest, ApplyTuple) {</div><div>+  auto T = std::make_tuple(1, 2, 3, 4);</div><div>+  auto U = llvm::apply_tuple(</div><div>+      [](int A, int B, int C, int D) {</div><div>+        return std::make_tuple(A - B, B - C, C - D, D - A);</div><div>+      },</div><div>+      T);</div><div>+</div><div>+  EXPECT_EQ(-1, std::get<0>(U));</div><div>+  EXPECT_EQ(-1, std::get<1>(U));</div><div>+  EXPECT_EQ(-1, std::get<2>(U));</div><div>+  EXPECT_EQ(3, std::get<3>(U));</div><div>+</div><div>+  auto V = llvm::apply_tuple(</div><div>+      [](int A, int B, int C, int D) {</div><div>+        return std::make_tuple(std::make_pair(A, char('A' + A)),</div><div>+                               std::make_pair(B, char('A' + B)),</div><div>+                               std::make_pair(C, char('A' + C)), D);</div><div>+      },</div><div>+      T);</div><div>+</div><div>+  EXPECT_EQ(std::make_pair(1, 'B'), std::get<0>(V));</div><div>+  EXPECT_EQ(std::make_pair(2, 'C'), std::get<1>(V));</div><div>+  EXPECT_EQ(std::make_pair(3, 'D'), std::get<2>(V));</div><div>+  EXPECT_EQ(4, std::get<3>(V));</div><div>+}</div><div>+</div><div>+struct deref_iterator_tuple {</div><div>+  template <typename... Iters> auto operator()(Iters &&... Items) {</div><div>+    return std::make_tuple(*Items...);</div><div>+  }</div><div>+};</div><div>+</div><div>+struct increment_iterator_tuple {</div><div>+  template <typename... Iters> auto operator()(Iters &&... Items) {</div><div>+    return std::make_tuple(++Items...);</div><div>+  }</div><div>+};</div><div>+</div><div>+TEST(STLExtrasTest, ApplyTupleVariadic) {</div><div>+  std::vector<int> A = {1, 2, 3};</div><div>+  std::vector<char> B = {'A', 'B', 'C'};</div><div>+  std::vector<std::string> C = {"A", "B", "C"};</div><div>+</div><div>+  auto Iters = std::make_tuple(A.begin(), B.begin(), C.begin());</div><div>+  auto Values = apply_tuple(deref_iterator_tuple(), Iters);</div><div>+</div><div>+  static_assert(</div><div>+      std::is_same<std::tuple<int, char, std::string>, decltype(Values)>::value,</div><div>+      "Incorrect tuple type!");</div><div>+</div><div>+  EXPECT_EQ(1, std::get<0>(Values));</div><div>+  EXPECT_EQ('A', std::get<1>(Values));</div><div>+  EXPECT_EQ("A", std::get<2>(Values));</div><div>+</div><div>+  Iters = apply_tuple(increment_iterator_tuple(), Iters);</div><div>+  Values = apply_tuple(deref_iterator_tuple(), Iters);</div><div>+</div><div>+  EXPECT_EQ(2, std::get<0>(Values));</div><div>+  EXPECT_EQ('B', std::get<1>(Values));</div><div>+  EXPECT_EQ("B", std::get<2>(Values));</div><div>+}</div><div> }</div></div></div>