1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
10 | |
11 | // type_traits |
12 | // common_reference |
13 | |
14 | #include <tuple> |
15 | #include <type_traits> |
16 | #include <utility> |
17 | |
18 | #include "test_macros.h" |
19 | |
20 | template <class T> |
21 | constexpr bool has_type = requires { |
22 | typename T::type; |
23 | }; |
24 | |
25 | // A slightly simplified variation of std::tuple |
26 | template <class...> |
27 | struct UserTuple {}; |
28 | |
29 | template <class, class, class> |
30 | struct Tuple_helper {}; |
31 | template <class... Ts, class... Us> |
32 | struct Tuple_helper<std::void_t<std::common_reference_t<Ts, Us>...>, UserTuple<Ts...>, UserTuple<Us...> > { |
33 | using type = UserTuple<std::common_reference_t<Ts, Us>...>; |
34 | }; |
35 | |
36 | namespace std { |
37 | template <class... Ts, class... Us, template <class> class TQual, template <class> class UQual> |
38 | struct basic_common_reference< ::UserTuple<Ts...>, ::UserTuple<Us...>, TQual, UQual> |
39 | : ::Tuple_helper<void, UserTuple<TQual<Ts>...>, UserTuple<UQual<Us>...> > {}; |
40 | } // namespace std |
41 | |
42 | struct X2 {}; |
43 | struct Y2 {}; |
44 | struct Z2 {}; |
45 | |
46 | namespace std { |
47 | template <> |
48 | struct common_type<X2, Y2> { |
49 | using type = Z2; |
50 | }; |
51 | template <> |
52 | struct common_type<Y2, X2> { |
53 | using type = Z2; |
54 | }; |
55 | } // namespace std |
56 | |
57 | // (6.1) |
58 | // -- If sizeof...(T) is zero, there shall be no member type. |
59 | static_assert(!has_type<std::common_reference<> >); |
60 | |
61 | // (6.2) |
62 | // -- Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the |
63 | // pack T. The member typedef type shall denote the same type as T0. |
64 | static_assert(std::is_same_v<std::common_reference_t<void>, void>); |
65 | static_assert(std::is_same_v<std::common_reference_t<int>, int>); |
66 | static_assert(std::is_same_v<std::common_reference_t<int&>, int&>); |
67 | static_assert(std::is_same_v<std::common_reference_t<int&&>, int&&>); |
68 | static_assert(std::is_same_v<std::common_reference_t<int const>, int const>); |
69 | static_assert(std::is_same_v<std::common_reference_t<int const&>, int const&>); |
70 | static_assert(std::is_same_v<std::common_reference_t<int const&&>, int const&&>); |
71 | static_assert(std::is_same_v<std::common_reference_t<int volatile[]>, int volatile[]>); |
72 | static_assert(std::is_same_v<std::common_reference_t<int volatile (&)[]>, int volatile (&)[]>); |
73 | static_assert(std::is_same_v<std::common_reference_t<int volatile (&&)[]>, int volatile (&&)[]>); |
74 | static_assert(std::is_same_v<std::common_reference_t<void (&)()>, void (&)()>); |
75 | static_assert(std::is_same_v<std::common_reference_t<void (&&)()>, void (&&)()>); |
76 | |
77 | // (6.3) |
78 | // -- Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in |
79 | // the pack T. Then |
80 | // (6.3.1) |
81 | // -- If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed, |
82 | // then the member typedef type denotes that type. |
83 | struct B {}; |
84 | struct D : B {}; |
85 | static_assert(std::is_same_v<std::common_reference_t<B&, D&>, B&>); |
86 | static_assert(std::is_same_v<std::common_reference_t<B const&, D&>, B const&>); |
87 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&>, B const&>); |
88 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&, D&>, B const&>); |
89 | static_assert(std::is_same_v<std::common_reference_t<B&, D&, B&, D&>, B&>); |
90 | |
91 | static_assert(std::is_same_v<std::common_reference_t<B&&, D&&>, B&&>); |
92 | static_assert(std::is_same_v<std::common_reference_t<B const&&, D&&>, B const&&>); |
93 | static_assert(std::is_same_v<std::common_reference_t<B&&, D const&&>, B const&&>); |
94 | static_assert(std::is_same_v<std::common_reference_t<B&, D&&>, B const&>); |
95 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&&>, B const&>); |
96 | static_assert(std::is_same_v<std::common_reference_t<B const&, D&&>, B const&>); |
97 | |
98 | static_assert(std::is_same_v<std::common_reference_t<B&&, D&>, B const&>); |
99 | static_assert(std::is_same_v<std::common_reference_t<B&&, D const&>, B const&>); |
100 | static_assert(std::is_same_v<std::common_reference_t<B const&&, D&>, B const&>); |
101 | |
102 | static_assert(std::is_same_v<std::common_reference_t<int const&, int volatile&>, int const volatile&>); |
103 | static_assert(std::is_same_v<std::common_reference_t<int const volatile&&, int volatile&&>, int const volatile&&>); |
104 | |
105 | static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&&)[10]>, int const (&)[10]>); |
106 | static_assert(std::is_same_v<std::common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile (&)[10]>); |
107 | |
108 | // (6.3.2) |
109 | // -- Otherwise, if basic_common_reference<remove_cvref_t<T1>, |
110 | // remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, then the |
111 | // member typedef type denotes that type. |
112 | static_assert(std::is_same_v<std::common_reference_t<const UserTuple<int, short>&, UserTuple<int&, short volatile&>>, |
113 | UserTuple<const int&, const volatile short&>>); |
114 | |
115 | static_assert(std::is_same_v<std::common_reference_t<volatile UserTuple<int, short>&, const UserTuple<int, short>&>, |
116 | const volatile UserTuple<int, short>&>); |
117 | |
118 | // (6.3.3) |
119 | // -- Otherwise, if COND_RES(T1, T2) is well-formed, then the member typedef |
120 | // type denotes that type. |
121 | static_assert(std::is_same_v<std::common_reference_t<void, void>, void>); |
122 | static_assert(std::is_same_v<std::common_reference_t<int, short>, int>); |
123 | static_assert(std::is_same_v<std::common_reference_t<int, short&>, int>); |
124 | static_assert(std::is_same_v<std::common_reference_t<int&, short&>, int>); |
125 | static_assert(std::is_same_v<std::common_reference_t<int&, short>, int>); |
126 | |
127 | // tricky volatile reference case |
128 | static_assert(std::is_same_v<std::common_reference_t<int&&, int volatile&>, int>); |
129 | static_assert(std::is_same_v<std::common_reference_t<int volatile&, int&&>, int>); |
130 | |
131 | static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&)[11]>, int*>); |
132 | |
133 | // https://github.com/ericniebler/stl2/issues/338 |
134 | struct MyIntRef { |
135 | MyIntRef(int&); |
136 | }; |
137 | static_assert(std::is_same_v<std::common_reference_t<int&, MyIntRef>, MyIntRef>); |
138 | |
139 | // (6.3.4) |
140 | // -- Otherwise, if common_type_t<T1, T2> is well-formed, then the member |
141 | // typedef type denotes that type. |
142 | struct moveonly { |
143 | moveonly() = default; |
144 | moveonly(moveonly&&) = default; |
145 | moveonly& operator=(moveonly&&) = default; |
146 | }; |
147 | struct moveonly2 : moveonly {}; |
148 | |
149 | static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly>, moveonly>); |
150 | static_assert(std::is_same_v<std::common_reference_t<moveonly2 const&, moveonly>, moveonly>); |
151 | static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly2>, moveonly>); |
152 | |
153 | static_assert(std::is_same_v<std::common_reference_t<X2&, Y2 const&>, Z2>); |
154 | |
155 | // (6.3.5) |
156 | // -- Otherwise, there shall be no member type. |
157 | static_assert(!has_type<std::common_reference<volatile UserTuple<short>&, const UserTuple<int, short>&> >); |
158 | |
159 | // (6.4) |
160 | // -- Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, |
161 | // respectively, denote the first, second, and (pack of) remaining types |
162 | // comprising T. Let C be the type common_reference_t<T1, T2>. Then: |
163 | // (6.4.1) |
164 | // -- If there is such a type C, the member typedef type shall denote the |
165 | // same type, if any, as common_reference_t<C, Rest...>. |
166 | static_assert(std::is_same_v<std::common_reference_t<int, int, int>, int>); |
167 | static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, int volatile&>, int const volatile&>); |
168 | static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, float&>, float>); |
169 | |
170 | // (6.4.2) |
171 | // -- Otherwise, there shall be no member type. |
172 | static_assert(!has_type<std::common_reference<int, short, int, char*> >); |
173 | |
174 | #if TEST_STD_VER > 20 |
175 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, int>>, std::tuple<int, int>>); |
176 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, long>, std::tuple<long, int>>, std::tuple<long, long>>); |
177 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const int&>, std::tuple<const int&, int>>, |
178 | std::tuple<const int&, int>>); |
179 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, volatile int&>, std::tuple<volatile int&, int>>, |
180 | std::tuple<volatile int&, int>>); |
181 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const volatile int&>, std::tuple<const volatile int&, int>>, |
182 | std::tuple<const volatile int&, int>>); |
183 | static_assert(!has_type<std::common_reference_t<std::tuple<const int&, volatile int&>, std::tuple<volatile int&, const int&>>>); |
184 | |
185 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>); |
186 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>); |
187 | static_assert(!has_type<std::common_reference<std::tuple<int, const X2>, std::tuple<float, const Z2>>>); |
188 | static_assert(!has_type<std::common_reference<std::tuple<int, X2>, std::tuple<float, Z2>>>); |
189 | static_assert(!has_type<std::common_reference<std::tuple<int, X2>, int, X2>>); |
190 | |
191 | struct A {}; |
192 | template <template<class> class TQual, template<class> class UQual> |
193 | struct std::basic_common_reference<A, std::tuple<B>, TQual, UQual> { |
194 | using type = tuple<UQual<B>>; |
195 | }; |
196 | |
197 | static_assert(std::is_same_v<std::common_reference_t<A, std::tuple<B>, std::tuple<D>>, std::tuple<B>>); |
198 | |
199 | |
200 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, int>>, |
201 | std::pair<int, int>>); |
202 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, long>, std::pair<long, int>>, |
203 | std::pair<long, long>>); |
204 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const int&>, std::pair<const int&, int>>, |
205 | std::pair<const int&, int>>); |
206 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, volatile int&>, std::pair<volatile int&, int>>, |
207 | std::pair<volatile int&, int>>); |
208 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const volatile int&>, std::pair<const volatile int&, int>>, |
209 | std::pair<const volatile int&, int>>); |
210 | static_assert(!has_type<std::common_reference_t<std::pair<const int&, volatile int&>, |
211 | std::pair<volatile int&, const int&>>>); |
212 | |
213 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>); |
214 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>); |
215 | static_assert(!has_type<std::common_reference<std::pair<int, const X2>, std::pair<float, const Z2>>>); |
216 | static_assert(!has_type<std::common_reference<std::pair<int, X2>, std::pair<float, Z2>>>); |
217 | static_assert(!has_type<std::common_reference<std::pair<int, X2>, int, X2>>); |
218 | #endif |
219 | |