Tuple.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines functions for manipulating tuples
6 
7 #pragma once
8 
9 #include <tuple>
10 #include <utility>
11 
12 namespace tuple_impl_detail {
13 template <bool ReverseIteration, typename... Elements, typename N_aryOp,
14  typename... Args, size_t... Is>
15 constexpr inline void tuple_fold_impl(
16  const std::tuple<Elements...>& tupull, N_aryOp&& op,
18  Args&... args) noexcept(
19  noexcept(static_cast<void>(std::initializer_list<char>{
20  (static_cast<void>(
21  op(std::get<(ReverseIteration ? sizeof...(Elements) - 1 - Is : Is)>(
22  tupull),
23  args...)),
24  '0')...}))) {
25  constexpr size_t tuple_size = sizeof...(Elements);
26  static_cast<void>(std::initializer_list<char>{
27  (static_cast<void>(
28  op(std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
29  args...)),
30  '0')...});
31 }
32 
33 template <bool ReverseIteration, typename... Elements, typename N_aryOp,
34  typename... Args, size_t... Is>
35 constexpr inline void tuple_counted_fold_impl(
36  const std::tuple<Elements...>& tupull, N_aryOp&& op,
38  Args&... args) noexcept(
39  noexcept(static_cast<void>(std::initializer_list<char>{
40  (static_cast<void>(
41  op(std::get<(ReverseIteration ? sizeof...(Elements) - 1 - Is : Is)>(
42  tupull),
43  (ReverseIteration ? sizeof...(Elements) - 1 - Is : Is), args...)),
44  '0')...}))) {
45  constexpr size_t tuple_size = sizeof...(Elements);
46  static_cast<void>(std::initializer_list<char>{
47  (static_cast<void>(
48  op(std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
49  (ReverseIteration ? tuple_size - 1 - Is : Is), args...)),
50  '0')...});
51 }
52 
53 template <bool ReverseIteration, typename... Elements, typename N_aryOp,
54  typename... Args, size_t... Is>
55 constexpr inline void tuple_transform_impl(
56  const std::tuple<Elements...>& tupull, N_aryOp&& op,
58  Args&... args) noexcept(
59  noexcept(static_cast<void>(std::initializer_list<char>{
60  (static_cast<void>(op(
61  std::get<(ReverseIteration ? sizeof...(Elements) - 1 - Is : Is)>(
62  tupull),
64  size_t, (ReverseIteration ? sizeof...(Elements) - 1 - Is : Is)>{},
65  args...)),
66  '0')...}))) {
67  constexpr size_t tuple_size = sizeof...(Elements);
68  static_cast<void>(std::initializer_list<char>{(
69  static_cast<void>(op(
70  std::get<(ReverseIteration ? tuple_size - 1 - Is : Is)>(tupull),
71  std::integral_constant<size_t, (ReverseIteration ? tuple_size - 1 - Is
72  : Is)>{},
73  args...)),
74  '0')...});
75 }
76 } // namespace tuple_impl_detail
77 
78 // @{
79 /*!
80  * \ingroup UtilitiesGroup
81  * \brief Perform a fold over a std::tuple
82  *
83  * \details
84  * Iterates over the elements in a std::tuple `tuple` from left to right
85  * (left fold) calling `op(element, args...)` on each element in `tuple`. A
86  * right fold can be done by explicitly setting the first template parameter
87  * to true. Folds are easily implemented using `tuple_fold` by updating
88  * one of the `args...` at each iteration. If you need the index of the current
89  * element you can use the `tuple_counted_fold` variant. `tuple_counted_fold`
90  * passes the current index as the second argument to the Callable `op`. That
91  * is, `op(element, index, args...)`.
92  *
93  * \example
94  * The sum of a std::tuple of Arithmetics can be computed in several ways.
95  * First, you can use a lambda:
96  * \snippet Utilities/Test_Tuple.cpp tuple_fold_lambda
97  * You'll notice that `state` is taken by reference and mutated.
98  *
99  * You can do the same thing with a struct defined as
100  * \snippet Utilities/Test_Tuple.cpp tuple_fold_struct_defn
101  * and then using an instance of the struct
102  * \snippet Utilities/Test_Tuple.cpp tuple_fold_struct
103  *
104  * \note You are not able to pass a function pointer to `tuple_fold` or
105  * `tuple_counted_fold` because you cannot pass a pointer to a function
106  * template, only a function.
107  *
108  * \see expand_pack tuple_transform tuple_fold tuple_counted_fold std::tuple
109  */
110 template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
111  typename... Args>
112 constexpr inline void tuple_fold(
113  const std::tuple<Elements...>& tuple, N_aryOp&& op,
114  Args&&... args) noexcept(noexcept(tuple_impl_detail::
115  tuple_fold_impl<ReverseIteration>(
116  tuple, std::forward<N_aryOp>(op),
118  sizeof...(Elements)>{},
119  args...))) {
120  tuple_impl_detail::tuple_fold_impl<ReverseIteration>(
121  tuple, std::forward<N_aryOp>(op),
122  std::make_index_sequence<sizeof...(Elements)>{}, args...);
123 }
124 
125 template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
126  typename... Args>
127 constexpr inline void tuple_counted_fold(
128  const std::tuple<Elements...>& tuple, N_aryOp&& op,
129  Args&&... args) noexcept(noexcept(tuple_impl_detail::
130  tuple_counted_fold_impl<
131  ReverseIteration>(
132  tuple, std::forward<N_aryOp>(op),
134  sizeof...(Elements)>{},
135  args...))) {
136  tuple_impl_detail::tuple_counted_fold_impl<ReverseIteration>(
137  tuple, std::forward<N_aryOp>(op),
138  std::make_index_sequence<sizeof...(Elements)>{}, args...);
139 }
140 // @}
141 
142 /*!
143  * \ingroup UtilitiesGroup
144  * \brief Perform a transform over a std::tuple
145  *
146  * \details
147  * Iterates over the elements in a std::tuple `tuple` from left to right
148  * calling `op.operator()(element, index, args...)` on each element
149  * in `tuple`. A right-to-left transform can be done by explicitly setting
150  * the first template parameter to true. The second argument of the invokable
151  * will be a deduced `std::integral_constant<size_t, value>`, from which the
152  * current index can be extracted by using `decltype(index)::%value`.
153  * For a function object the `decltype(index)` can be replaced by the deduced
154  * type of `index`. For example,
155  * \snippet Utilities/Test_Tuple.cpp tuple_transform_negate
156  *
157  * Using `tuple_transform` with a generic lambda goes as follows,
158  * \snippet Utilities/Test_Tuple.cpp tuple_transform
159  *
160  * \see expand_pack tuple_fold tuple_counted_fold std::tuple
161  */
162 template <bool ReverseIteration = false, typename... Elements, typename N_aryOp,
163  typename... Args>
164 constexpr inline void tuple_transform(
165  const std::tuple<Elements...>& tuple, N_aryOp&& op,
166  Args&&... args) noexcept(noexcept(tuple_impl_detail::
167  tuple_transform_impl<
168  ReverseIteration>(
169  tuple, std::forward<N_aryOp>(op),
171  sizeof...(Elements)>{},
172  args...))) {
173  tuple_impl_detail::tuple_transform_impl<ReverseIteration>(
174  tuple, std::forward<N_aryOp>(op),
175  std::make_index_sequence<sizeof...(Elements)>{}, args...);
176 }
constexpr void tuple_transform(const std::tuple< Elements... > &tuple, N_aryOp &&op, Args &&... args) noexcept(noexcept(tuple_impl_detail::tuple_transform_impl< ReverseIteration >(tuple, std::forward< N_aryOp >(op), std::make_index_sequence< sizeof...(Elements)>{}, args...)))
Perform a transform over a std::tuple.
Definition: Tuple.hpp:164
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:649
constexpr void tuple_fold(const std::tuple< Elements... > &tuple, N_aryOp &&op, Args &&... args) noexcept(noexcept(tuple_impl_detail::tuple_fold_impl< ReverseIteration >(tuple, std::forward< N_aryOp >(op), std::make_index_sequence< sizeof...(Elements)>{}, args...)))
Perform a fold over a std::tuple.
Definition: Tuple.hpp:112
constexpr void tuple_counted_fold(const std::tuple< Elements... > &tuple, N_aryOp &&op, Args &&... args) noexcept(noexcept(tuple_impl_detail::tuple_counted_fold_impl< ReverseIteration >(tuple, std::forward< N_aryOp >(op), std::make_index_sequence< sizeof...(Elements)>{}, args...)))
Perform a fold over a std::tuple.
Definition: Tuple.hpp:127
Definition: Tuple.hpp:12