Skip to content

Commit 5a95388

Browse files
committed
C++17: Update tuple_transform_each().
Update from murrayc-tuple-utils: https://github.com/murraycu/murrayc-tuple-utils/commits/master
1 parent 1759faf commit 5a95388

File tree

1 file changed

+49
-82
lines changed

1 file changed

+49
-82
lines changed

sigc++/tuple-utils/tuple_transform_each.h

Lines changed: 49 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -18,88 +18,57 @@
1818
#ifndef SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
1919
#define SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
2020

21+
// #include <sigc++/tuple-utils/tuple_cat.h>
2122
#include <sigc++/tuple-utils/tuple_cdr.h>
2223
#include <sigc++/tuple-utils/tuple_end.h>
2324
#include <sigc++/tuple-utils/tuple_start.h>
2425
#include <type_traits>
2526

26-
namespace sigc
27-
{
27+
namespace sigc::internal {
2828

29-
namespace internal
30-
{
31-
32-
namespace detail
33-
{
29+
namespace detail {
3430

3531
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 {
3833
// TODO: Avoid the need to pass t_original all the way into the recursion?
3934
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+
}
10372
}
10473
};
10574

@@ -110,18 +79,16 @@ struct tuple_transform_each_impl<T_transformer, 0>
11079
* in the original tuple.
11180
*/
11281
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.
11786
constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
11887

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);
12190
}
12291

123-
} // namespace internal
124-
125-
} // namespace sigc
92+
} // namespace sigc::internal
12693

127-
#endif // SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
94+
#endif //SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H

0 commit comments

Comments
 (0)