Skip to content

Commit f329e47

Browse files
committed
fix universal: make ForwardLike conform to the standard
1 parent 22dbc4b commit f329e47

4 files changed

Lines changed: 361 additions & 20 deletions

File tree

universal/include/userver/utils/forward_like.hpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,35 @@
44
/// @brief @copybrief utils::ForwardLike
55

66
#include <type_traits>
7-
#include <utility>
87

98
USERVER_NAMESPACE_BEGIN
109

1110
namespace utils {
1211

13-
// Analogue of std::forward_like from c++23.
14-
template <typename TOwner, typename TMember>
15-
decltype(auto) ForwardLike(TMember& member) {
16-
if constexpr (std::is_lvalue_reference_v<TOwner> || std::is_lvalue_reference_v<TMember>) {
17-
return member;
18-
} else {
19-
return std::move(member);
20-
}
21-
}
12+
namespace impl {
13+
14+
template <typename T, typename U>
15+
struct ForwardLikeHelper;
16+
17+
template <typename T, typename U>
18+
struct ForwardLikeHelper<T&, U&> : std::type_identity<U&> {};
19+
20+
template <typename T, typename U>
21+
struct ForwardLikeHelper<const T&, U&> : std::type_identity<const U&> {};
22+
23+
template <typename T, typename U>
24+
struct ForwardLikeHelper<T&&, U&> : std::type_identity<U&&> {};
25+
26+
template <typename T, typename U>
27+
struct ForwardLikeHelper<const T&&, U&> : std::type_identity<const U&&> {};
28+
29+
} // namespace impl
2230

2331
// Analogue of std::forward_like from c++23.
2432
template <typename TOwner, typename TMember>
25-
decltype(auto) ForwardLike(const TMember& member) {
26-
return member;
33+
constexpr auto&& ForwardLike(TMember&& member) noexcept {
34+
using RType = impl::ForwardLikeHelper<TOwner&&, TMember&>::type;
35+
return static_cast<RType>(member);
2736
}
2837

2938
} // namespace utils

universal/include/userver/utils/struct_subsets.hpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,34 @@ constexpr auto IsDefinedAndAggregate(Args...) -> bool {
3434
return false;
3535
}
3636

37+
template <typename Superset, typename Field, typename T>
38+
auto&& GetSupersetField(T &t, InternalTag) noexcept {
39+
if constexpr (std::is_reference_v<Field>) {
40+
return std::forward<Field>(t);
41+
} else {
42+
return utils::ForwardLike<Superset>(t);
43+
}
44+
}
45+
46+
template <typename T>
47+
struct SubsetField : std::type_identity<T> {};
48+
49+
template <typename T>
50+
struct SubsetFieldRef : std::type_identity<const T&> {};
51+
52+
template <typename T>
53+
struct SubsetFieldRef<T&&> : std::type_identity<T&&> {};
54+
3755
} // namespace utils::impl
3856

3957
USERVER_NAMESPACE_END
4058

4159
/// @cond
4260

4361
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
44-
#define USERVER_IMPL_STRUCT_MAP(r, data, elem) \
45-
USERVER_NAMESPACE::utils::ForwardLike<OtherDeps, decltype(other.elem)>(other.elem),
62+
#define USERVER_IMPL_STRUCT_MAP(r, data, elem) \
63+
USERVER_NAMESPACE::utils::impl::GetSupersetField<OtherDeps, decltype(other.elem)>( \
64+
other.elem, USERVER_NAMESPACE::utils::impl::InternalTag{}),
4665

4766
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
4867
#define USERVER_IMPL_MAKE_FROM_SUPERSET(Self, ...) \
@@ -56,14 +75,14 @@ USERVER_NAMESPACE_END
5675
}
5776

5877
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
59-
#define USERVER_IMPL_STRUCT_SUBSET_MAP(r, data, elem) \
60-
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
61-
decltype(data::elem) elem;
78+
#define USERVER_IMPL_STRUCT_SUBSET_MAP(r, data, elem) \
79+
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
80+
USERVER_NAMESPACE::utils::impl::SubsetField<decltype(data::elem)>::type elem;
6281

6382
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
64-
#define USERVER_IMPL_STRUCT_SUBSET_REF_MAP(r, data, elem) \
65-
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
66-
std::add_const_t<decltype(data::elem)>& elem;
83+
#define USERVER_IMPL_STRUCT_SUBSET_REF_MAP(r, data, elem) \
84+
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
85+
USERVER_NAMESPACE::utils::impl::SubsetFieldRef<decltype(data::elem)>::type elem;
6786

6887
/// @endcond
6988

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include <userver/utils/forward_like.hpp>
2+
3+
#include <type_traits>
4+
#include <utility>
5+
6+
USERVER_NAMESPACE_BEGIN
7+
8+
namespace {
9+
10+
template <typename T, typename U>
11+
using ForwardLikeResult = decltype(utils::ForwardLike<T>(std::declval<U>()));
12+
13+
static_assert(std::is_same_v<ForwardLikeResult<int, int>, int&&>);
14+
static_assert(std::is_same_v<ForwardLikeResult<int, const int>, const int&&>);
15+
static_assert(std::is_same_v<ForwardLikeResult<int, volatile int>, volatile int&&>);
16+
static_assert(std::is_same_v<ForwardLikeResult<int, const volatile int>, const volatile int&&>);
17+
static_assert(std::is_same_v<ForwardLikeResult<int, int&>, int&&>);
18+
static_assert(std::is_same_v<ForwardLikeResult<int, const int&>, const int&&>);
19+
static_assert(std::is_same_v<ForwardLikeResult<int, volatile int&>, volatile int&&>);
20+
static_assert(std::is_same_v<ForwardLikeResult<int, const volatile int&>, const volatile int&&>);
21+
static_assert(std::is_same_v<ForwardLikeResult<int, int&&>, int&&>);
22+
static_assert(std::is_same_v<ForwardLikeResult<int, const int&&>, const int&&>);
23+
static_assert(std::is_same_v<ForwardLikeResult<int, volatile int&&>, volatile int&&>);
24+
static_assert(std::is_same_v<ForwardLikeResult<int, const volatile int&&>, const volatile int&&>);
25+
26+
static_assert(std::is_same_v<ForwardLikeResult<const int, int>, const int&&>);
27+
static_assert(std::is_same_v<ForwardLikeResult<const int, const int>, const int&&>);
28+
static_assert(std::is_same_v<ForwardLikeResult<const int, volatile int>, const volatile int&&>);
29+
static_assert(std::is_same_v<ForwardLikeResult<const int, const volatile int>, const volatile int&&>);
30+
static_assert(std::is_same_v<ForwardLikeResult<const int, int&>, const int&&>);
31+
static_assert(std::is_same_v<ForwardLikeResult<const int, const int&>, const int&&>);
32+
static_assert(std::is_same_v<ForwardLikeResult<const int, volatile int&>, const volatile int&&>);
33+
static_assert(std::is_same_v<ForwardLikeResult<const int, const volatile int&>, const volatile int&&>);
34+
static_assert(std::is_same_v<ForwardLikeResult<const int, int&&>, const int&&>);
35+
static_assert(std::is_same_v<ForwardLikeResult<const int, const int&&>, const int&&>);
36+
static_assert(std::is_same_v<ForwardLikeResult<const int, volatile int&&>, const volatile int&&>);
37+
static_assert(std::is_same_v<ForwardLikeResult<const int, const volatile int&&>, const volatile int&&>);
38+
39+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, int>, int&&>);
40+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const int>, const int&&>);
41+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, volatile int>, volatile int&&>);
42+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const volatile int>, const volatile int&&>);
43+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, int&>, int&&>);
44+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const int&>, const int&&>);
45+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, volatile int&>, volatile int&&>);
46+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const volatile int&>, const volatile int&&>);
47+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, int&&>, int&&>);
48+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const int&&>, const int&&>);
49+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, volatile int&&>, volatile int&&>);
50+
static_assert(std::is_same_v<ForwardLikeResult<volatile int, const volatile int&&>, const volatile int&&>);
51+
52+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, int>, const int&&>);
53+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const int>, const int&&>);
54+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, volatile int>, const volatile int&&>);
55+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const volatile int>, const volatile int&&>);
56+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, int&>, const int&&>);
57+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const int&>, const int&&>);
58+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, volatile int&>, const volatile int&&>);
59+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const volatile int&>, const volatile int&&>);
60+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, int&&>, const int&&>);
61+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const int&&>, const int&&>);
62+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, volatile int&&>, const volatile int&&>);
63+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int, const volatile int&&>, const volatile int&&>);
64+
65+
static_assert(std::is_same_v<ForwardLikeResult<int&, int>, int&>);
66+
static_assert(std::is_same_v<ForwardLikeResult<int&, const int>, const int&>);
67+
static_assert(std::is_same_v<ForwardLikeResult<int&, volatile int>, volatile int&>);
68+
static_assert(std::is_same_v<ForwardLikeResult<int&, const volatile int>, const volatile int&>);
69+
static_assert(std::is_same_v<ForwardLikeResult<int&, int&>, int&>);
70+
static_assert(std::is_same_v<ForwardLikeResult<int&, const int&>, const int&>);
71+
static_assert(std::is_same_v<ForwardLikeResult<int&, volatile int&>, volatile int&>);
72+
static_assert(std::is_same_v<ForwardLikeResult<int&, const volatile int&>, const volatile int&>);
73+
static_assert(std::is_same_v<ForwardLikeResult<int&, int&&>, int&>);
74+
static_assert(std::is_same_v<ForwardLikeResult<int&, const int&&>, const int&>);
75+
static_assert(std::is_same_v<ForwardLikeResult<int&, volatile int&&>, volatile int&>);
76+
static_assert(std::is_same_v<ForwardLikeResult<int&, const volatile int&&>, const volatile int&>);
77+
78+
static_assert(std::is_same_v<ForwardLikeResult<const int&, int>, const int&>);
79+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const int>, const int&>);
80+
static_assert(std::is_same_v<ForwardLikeResult<const int&, volatile int>, const volatile int&>);
81+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const volatile int>, const volatile int&>);
82+
static_assert(std::is_same_v<ForwardLikeResult<const int&, int&>, const int&>);
83+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const int&>, const int&>);
84+
static_assert(std::is_same_v<ForwardLikeResult<const int&, volatile int&>, const volatile int&>);
85+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const volatile int&>, const volatile int&>);
86+
static_assert(std::is_same_v<ForwardLikeResult<const int&, int&&>, const int&>);
87+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const int&&>, const int&>);
88+
static_assert(std::is_same_v<ForwardLikeResult<const int&, volatile int&&>, const volatile int&>);
89+
static_assert(std::is_same_v<ForwardLikeResult<const int&, const volatile int&&>, const volatile int&>);
90+
91+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, int>, int&>);
92+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const int>, const int&>);
93+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, volatile int>, volatile int&>);
94+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const volatile int>, const volatile int&>);
95+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, int&>, int&>);
96+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const int&>, const int&>);
97+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, volatile int&>, volatile int&>);
98+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const volatile int&>, const volatile int&>);
99+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, int&&>, int&>);
100+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const int&&>, const int&>);
101+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, volatile int&&>, volatile int&>);
102+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&, const volatile int&&>, const volatile int&>);
103+
104+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, int>, const int&>);
105+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const int>, const int&>);
106+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, volatile int>, const volatile int&>);
107+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const volatile int>, const volatile int&>);
108+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, int&>, const int&>);
109+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const int&>, const int&>);
110+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, volatile int&>, const volatile int&>);
111+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const volatile int&>, const volatile int&>);
112+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, int&&>, const int&>);
113+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const int&&>, const int&>);
114+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, volatile int&&>, const volatile int&>);
115+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&, const volatile int&&>, const volatile int&>);
116+
117+
static_assert(std::is_same_v<ForwardLikeResult<int&&, int>, int&&>);
118+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const int>, const int&&>);
119+
static_assert(std::is_same_v<ForwardLikeResult<int&&, volatile int>, volatile int&&>);
120+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const volatile int>, const volatile int&&>);
121+
static_assert(std::is_same_v<ForwardLikeResult<int&&, int&>, int&&>);
122+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const int&>, const int&&>);
123+
static_assert(std::is_same_v<ForwardLikeResult<int&&, volatile int&>, volatile int&&>);
124+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const volatile int&>, const volatile int&&>);
125+
static_assert(std::is_same_v<ForwardLikeResult<int&&, int&&>, int&&>);
126+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const int&&>, const int&&>);
127+
static_assert(std::is_same_v<ForwardLikeResult<int&&, volatile int&&>, volatile int&&>);
128+
static_assert(std::is_same_v<ForwardLikeResult<int&&, const volatile int&&>, const volatile int&&>);
129+
130+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, int>, const int&&>);
131+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const int>, const int&&>);
132+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, volatile int>, const volatile int&&>);
133+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const volatile int>, const volatile int&&>);
134+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, int&>, const int&&>);
135+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const int&>, const int&&>);
136+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, volatile int&>, const volatile int&&>);
137+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const volatile int&>, const volatile int&&>);
138+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, int&&>, const int&&>);
139+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const int&&>, const int&&>);
140+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, volatile int&&>, const volatile int&&>);
141+
static_assert(std::is_same_v<ForwardLikeResult<const int&&, const volatile int&&>, const volatile int&&>);
142+
143+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, int>, int&&>);
144+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const int>, const int&&>);
145+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, volatile int>, volatile int&&>);
146+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const volatile int>, const volatile int&&>);
147+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, int&>, int&&>);
148+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const int&>, const int&&>);
149+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, volatile int&>, volatile int&&>);
150+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const volatile int&>, const volatile int&&>);
151+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, int&&>, int&&>);
152+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const int&&>, const int&&>);
153+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, volatile int&&>, volatile int&&>);
154+
static_assert(std::is_same_v<ForwardLikeResult<volatile int&&, const volatile int&&>, const volatile int&&>);
155+
156+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, int>, const int&&>);
157+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const int>, const int&&>);
158+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, volatile int>, const volatile int&&>);
159+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const volatile int>, const volatile int&&>);
160+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, int&>, const int&&>);
161+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const int&>, const int&&>);
162+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, volatile int&>, const volatile int&&>);
163+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const volatile int&>, const volatile int&&>);
164+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, int&&>, const int&&>);
165+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const int&&>, const int&&>);
166+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, volatile int&&>, const volatile int&&>);
167+
static_assert(std::is_same_v<ForwardLikeResult<const volatile int&&, const volatile int&&>, const volatile int&&>);
168+
169+
} // namespace
170+
171+
USERVER_NAMESPACE_END

0 commit comments

Comments
 (0)