18
18
#ifndef SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
19
19
#define SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
20
20
21
+ // #include <sigc++/tuple-utils/tuple_cat.h>
21
22
#include < sigc++/tuple-utils/tuple_cdr.h>
22
23
#include < sigc++/tuple-utils/tuple_end.h>
23
24
#include < sigc++/tuple-utils/tuple_start.h>
24
25
#include < type_traits>
25
26
26
- namespace sigc
27
- {
27
+ namespace sigc ::internal {
28
28
29
- namespace internal
30
- {
31
-
32
- namespace detail
33
- {
29
+ namespace detail {
34
30
35
31
template <template <typename > class T_transformer , std::size_t size_from_index>
36
- struct tuple_transform_each_impl
37
- {
32
+ struct tuple_transform_each_impl {
38
33
// TODO: Avoid the need to pass t_original all the way into the recursion?
39
34
template <typename T_current, typename T_original>
40
- constexpr static decltype (auto ) tuple_transform_each(T_current&& t, T_original& t_original)
41
- {
42
- // We use std::decay_t<> because tuple_size is not defined for references.
43
- constexpr auto size = std::tuple_size<std::decay_t <T_current>>::value;
44
- static_assert (size > 1 , " size must be more than 0." );
45
-
46
- constexpr auto index = size - size_from_index;
47
- static_assert (index >= 0 , " unexpected index." );
48
-
49
- using from_element_type = typename std::tuple_element<index, std::decay_t <T_original>>::type;
50
- using to_element_type = typename std::result_of<decltype (
51
- &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
52
- const auto t_element = std::tuple<to_element_type>(
53
- T_transformer<from_element_type>::transform (std::get<index>(t_original)));
54
-
55
- const auto t_start = tuple_start<index>(std::forward<T_current>(t));
56
-
57
- // t_end's elements will be copies of the elements in t, so this method's
58
- // caller won't see the changes made in the subsequent call of
59
- // tuple_transform_each() on those copies. That's why we pass t_original
60
- // through too, so we can modify that directly.
61
- // the const version (tuple_transform_each_const()) doesn't have to worry
62
- // about this, though avoiding copying would be more efficient.
63
- const auto t_end = tuple_end<size - index - 1 >(t);
64
-
65
- auto t_with_transformed_element = std::tuple_cat (t_start, t_element, t_end);
66
- return tuple_transform_each_impl<T_transformer, size_from_index - 1 >::tuple_transform_each (
67
- t_with_transformed_element, t_original);
68
- }
69
- };
70
-
71
- template <template <typename > class T_transformer >
72
- struct tuple_transform_each_impl <T_transformer, 1 >
73
- {
74
- template <typename T_current, typename T_original>
75
- constexpr static decltype (auto ) tuple_transform_each(T_current&& t, T_original& t_original)
76
- {
77
- // We use std::decay_t<> because tuple_size is not defined for references.
78
- constexpr auto size = std::tuple_size<std::decay_t <T_current>>::value;
79
- static_assert (size > 0 , " size must be more than 0." );
80
-
81
- constexpr auto index = size - 1 ;
82
- static_assert (index >= 0 , " unexpected index." );
83
-
84
- using from_element_type = typename std::tuple_element<index, T_original>::type;
85
- using to_element_type = typename std::result_of<decltype (
86
- &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
87
- const auto tuple_element = std::tuple<to_element_type>(
88
- T_transformer<from_element_type>::transform (std::get<index>(t_original)));
89
-
90
- const auto tuple_rest = tuple_start<size - 1 >(std::forward<T_current>(t));
91
- return std::tuple_cat (tuple_rest, tuple_element);
92
- }
93
- };
94
-
95
- template <template <typename > class T_transformer >
96
- struct tuple_transform_each_impl <T_transformer, 0 >
97
- {
98
- template <typename T_current, typename T_original>
99
- constexpr static decltype (auto ) tuple_transform_each(T_current&& t, T_original& /* t_original */ )
100
- {
101
- // Do nothing because the tuple has no elements.
102
- return std::forward<T_current>(t);
35
+ constexpr
36
+ static decltype (auto )
37
+ tuple_transform_each(T_current&& t, T_original& t_original) {
38
+ if constexpr (size_from_index == 0 ) {
39
+ // Do nothing because the tuple has no elements.
40
+ return std::forward<T_current>(t);
41
+ } else { // TODO: Should this compile without using else to contain the alternative code?
42
+ // We use std::decay_t<> because tuple_size is not defined for references.
43
+ constexpr auto size = std::tuple_size<std::decay_t <T_current>>::value;
44
+ constexpr auto index = size - size_from_index;
45
+ static_assert (index >= 0 , " unexpected index." );
46
+
47
+ using from_element_type = typename std::tuple_element<index, std::decay_t <T_original>>::type;
48
+ using to_element_type = typename std::result_of<decltype (
49
+ &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
50
+ const auto t_element =
51
+ std::tuple<to_element_type>(T_transformer<from_element_type>::transform (std::get<index>(t_original)));
52
+
53
+ if constexpr (size_from_index == 1 ) {
54
+ const auto tuple_rest = tuple_start<size - 1 >(std::forward<T_current>(t));
55
+ return std::tuple_cat (tuple_rest, t_element);
56
+ } else {
57
+ const auto t_start = tuple_start<index>(std::forward<T_current>(t));
58
+
59
+ // t_end's elements will be copies of the elements in t, so this method's
60
+ // caller won't see the changes made in the subsequent call of
61
+ // tuple_transform_each() on those copies. That's why we pass t_original
62
+ // through too, so we can modify that directly.
63
+ // the const version (tuple_transform_each_const()) doesn't have to worry
64
+ // about this, though avoiding copying would be more efficient.
65
+ const auto t_end = tuple_end<size - index - 1 >(t);
66
+
67
+ auto t_with_transformed_element = std::tuple_cat (t_start, t_element, t_end);
68
+ return tuple_transform_each_impl<T_transformer,
69
+ size_from_index - 1 >::tuple_transform_each (t_with_transformed_element, t_original);
70
+ }
71
+ }
103
72
}
104
73
};
105
74
@@ -110,18 +79,16 @@ struct tuple_transform_each_impl<T_transformer, 0>
110
79
* in the original tuple.
111
80
*/
112
81
template <template <typename > class T_transformer , typename T>
113
- constexpr decltype ( auto )
114
- tuple_transform_each(T&& t )
115
- {
116
- // We use std::decay_t<> because tuple_size is not defined for references.
82
+ constexpr
83
+ decltype ( auto )
84
+ tuple_transform_each (T&& t) {
85
+ // We use std::decay_t<> because tuple_size is not defined for references.
117
86
constexpr auto size = std::tuple_size<std::decay_t <T>>::value;
118
87
119
- return detail::tuple_transform_each_impl<T_transformer, size>:: tuple_transform_each (
120
- std::forward<T>(t), t);
88
+ return detail::tuple_transform_each_impl<T_transformer,
89
+ size>:: tuple_transform_each ( std::forward<T>(t), t);
121
90
}
122
91
123
- } // namespace internal
124
-
125
- } // namespace sigc
92
+ } // namespace sigc::internal
126
93
127
- #endif // SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
94
+ #endif // SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
0 commit comments