| 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 | template <class... Ts, class... Us, template <class> class TQual, template <class> class UQual> |
| 37 | struct std::basic_common_reference< ::UserTuple<Ts...>, ::UserTuple<Us...>, TQual, UQual> |
| 38 | : ::Tuple_helper<void, UserTuple<TQual<Ts>...>, UserTuple<UQual<Us>...> > {}; |
| 39 | |
| 40 | struct X2 {}; |
| 41 | struct Y2 {}; |
| 42 | struct Z2 {}; |
| 43 | |
| 44 | template <> |
| 45 | struct std::common_type<X2, Y2> { |
| 46 | using type = Z2; |
| 47 | }; |
| 48 | template <> |
| 49 | struct std::common_type<Y2, X2> { |
| 50 | using type = Z2; |
| 51 | }; |
| 52 | |
| 53 | // (6.1) |
| 54 | // -- If sizeof...(T) is zero, there shall be no member type. |
| 55 | static_assert(!has_type<std::common_reference<> >); |
| 56 | |
| 57 | // (6.2) |
| 58 | // -- Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the |
| 59 | // pack T. The member typedef type shall denote the same type as T0. |
| 60 | static_assert(std::is_same_v<std::common_reference_t<void>, void>); |
| 61 | static_assert(std::is_same_v<std::common_reference_t<int>, int>); |
| 62 | static_assert(std::is_same_v<std::common_reference_t<int&>, int&>); |
| 63 | static_assert(std::is_same_v<std::common_reference_t<int&&>, int&&>); |
| 64 | static_assert(std::is_same_v<std::common_reference_t<int const>, int const>); |
| 65 | static_assert(std::is_same_v<std::common_reference_t<int const&>, int const&>); |
| 66 | static_assert(std::is_same_v<std::common_reference_t<int const&&>, int const&&>); |
| 67 | static_assert(std::is_same_v<std::common_reference_t<int volatile[]>, int volatile[]>); |
| 68 | static_assert(std::is_same_v<std::common_reference_t<int volatile (&)[]>, int volatile (&)[]>); |
| 69 | static_assert(std::is_same_v<std::common_reference_t<int volatile (&&)[]>, int volatile (&&)[]>); |
| 70 | static_assert(std::is_same_v<std::common_reference_t<void (&)()>, void (&)()>); |
| 71 | static_assert(std::is_same_v<std::common_reference_t<void (&&)()>, void (&&)()>); |
| 72 | |
| 73 | // (6.3) |
| 74 | // -- Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in |
| 75 | // the pack T. Then |
| 76 | // (6.3.1) |
| 77 | // -- If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed, |
| 78 | // then the member typedef type denotes that type. |
| 79 | struct B {}; |
| 80 | struct D : B {}; |
| 81 | static_assert(std::is_same_v<std::common_reference_t<B&, D&>, B&>); |
| 82 | static_assert(std::is_same_v<std::common_reference_t<B const&, D&>, B const&>); |
| 83 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&>, B const&>); |
| 84 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&, D&>, B const&>); |
| 85 | static_assert(std::is_same_v<std::common_reference_t<B&, D&, B&, D&>, B&>); |
| 86 | |
| 87 | static_assert(std::is_same_v<std::common_reference_t<B&&, D&&>, B&&>); |
| 88 | static_assert(std::is_same_v<std::common_reference_t<B const&&, D&&>, B const&&>); |
| 89 | static_assert(std::is_same_v<std::common_reference_t<B&&, D const&&>, B const&&>); |
| 90 | static_assert(std::is_same_v<std::common_reference_t<B&, D&&>, B const&>); |
| 91 | static_assert(std::is_same_v<std::common_reference_t<B&, D const&&>, B const&>); |
| 92 | static_assert(std::is_same_v<std::common_reference_t<B const&, D&&>, B const&>); |
| 93 | |
| 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<int const&, int volatile&>, int const volatile&>); |
| 99 | static_assert(std::is_same_v<std::common_reference_t<int const volatile&&, int volatile&&>, int const volatile&&>); |
| 100 | |
| 101 | static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&&)[10]>, int const (&)[10]>); |
| 102 | static_assert(std::is_same_v<std::common_reference_t<int const (&)[10], int volatile (&)[10]>, int const volatile (&)[10]>); |
| 103 | |
| 104 | // (6.3.2) |
| 105 | // -- Otherwise, if basic_common_reference<remove_cvref_t<T1>, |
| 106 | // remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, then the |
| 107 | // member typedef type denotes that type. |
| 108 | static_assert(std::is_same_v<std::common_reference_t<const UserTuple<int, short>&, UserTuple<int&, short volatile&>>, |
| 109 | UserTuple<const int&, const volatile short&>>); |
| 110 | |
| 111 | static_assert(std::is_same_v<std::common_reference_t<volatile UserTuple<int, short>&, const UserTuple<int, short>&>, |
| 112 | const volatile UserTuple<int, short>&>); |
| 113 | |
| 114 | // (6.3.3) |
| 115 | // -- Otherwise, if COND_RES(T1, T2) is well-formed, then the member typedef |
| 116 | // type denotes that type. |
| 117 | static_assert(std::is_same_v<std::common_reference_t<void, void>, void>); |
| 118 | static_assert(std::is_same_v<std::common_reference_t<int, short>, int>); |
| 119 | static_assert(std::is_same_v<std::common_reference_t<int, short&>, int>); |
| 120 | static_assert(std::is_same_v<std::common_reference_t<int&, short&>, int>); |
| 121 | static_assert(std::is_same_v<std::common_reference_t<int&, short>, int>); |
| 122 | |
| 123 | // tricky volatile reference case |
| 124 | static_assert(std::is_same_v<std::common_reference_t<int&&, int volatile&>, int>); |
| 125 | static_assert(std::is_same_v<std::common_reference_t<int volatile&, int&&>, int>); |
| 126 | |
| 127 | static_assert(std::is_same_v<std::common_reference_t<int (&)[10], int (&)[11]>, int*>); |
| 128 | |
| 129 | // https://github.com/ericniebler/stl2/issues/338 |
| 130 | struct MyIntRef { |
| 131 | MyIntRef(int&); |
| 132 | }; |
| 133 | static_assert(std::is_same_v<std::common_reference_t<int&, MyIntRef>, MyIntRef>); |
| 134 | |
| 135 | // (6.3.4) |
| 136 | // -- Otherwise, if common_type_t<T1, T2> is well-formed, then the member |
| 137 | // typedef type denotes that type. |
| 138 | struct moveonly { |
| 139 | moveonly() = default; |
| 140 | moveonly(moveonly&&) = default; |
| 141 | moveonly& operator=(moveonly&&) = default; |
| 142 | }; |
| 143 | struct moveonly2 : moveonly {}; |
| 144 | |
| 145 | static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly>, moveonly>); |
| 146 | static_assert(std::is_same_v<std::common_reference_t<moveonly2 const&, moveonly>, moveonly>); |
| 147 | static_assert(std::is_same_v<std::common_reference_t<moveonly const&, moveonly2>, moveonly>); |
| 148 | |
| 149 | static_assert(std::is_same_v<std::common_reference_t<X2&, Y2 const&>, Z2>); |
| 150 | |
| 151 | // (6.3.5) |
| 152 | // -- Otherwise, there shall be no member type. |
| 153 | static_assert(!has_type<std::common_reference<volatile UserTuple<short>&, const UserTuple<int, short>&> >); |
| 154 | |
| 155 | // (6.4) |
| 156 | // -- Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, |
| 157 | // respectively, denote the first, second, and (pack of) remaining types |
| 158 | // comprising T. Let C be the type common_reference_t<T1, T2>. Then: |
| 159 | // (6.4.1) |
| 160 | // -- If there is such a type C, the member typedef type shall denote the |
| 161 | // same type, if any, as common_reference_t<C, Rest...>. |
| 162 | static_assert(std::is_same_v<std::common_reference_t<int, int, int>, int>); |
| 163 | static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, int volatile&>, int const volatile&>); |
| 164 | static_assert(std::is_same_v<std::common_reference_t<int&&, int const&, float&>, float>); |
| 165 | |
| 166 | // (6.4.2) |
| 167 | // -- Otherwise, there shall be no member type. |
| 168 | static_assert(!has_type<std::common_reference<int, short, int, char*> >); |
| 169 | |
| 170 | #if TEST_STD_VER > 20 |
| 171 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, int>>, std::tuple<int, int>>); |
| 172 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, long>, std::tuple<long, int>>, std::tuple<long, long>>); |
| 173 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const int&>, std::tuple<const int&, int>>, |
| 174 | std::tuple<const int&, int>>); |
| 175 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, volatile int&>, std::tuple<volatile int&, int>>, |
| 176 | std::tuple<volatile int&, int>>); |
| 177 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int&, const volatile int&>, std::tuple<const volatile int&, int>>, |
| 178 | std::tuple<const volatile int&, int>>); |
| 179 | static_assert(!has_type<std::common_reference_t<std::tuple<const int&, volatile int&>, std::tuple<volatile int&, const int&>>>); |
| 180 | |
| 181 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>); |
| 182 | static_assert(std::is_same_v<std::common_reference_t<std::tuple<int, X2>, std::tuple<int, Y2>>, std::tuple<int, Z2>>); |
| 183 | static_assert(!has_type<std::common_reference<std::tuple<int, const X2>, std::tuple<float, const Z2>>>); |
| 184 | static_assert(!has_type<std::common_reference<std::tuple<int, X2>, std::tuple<float, Z2>>>); |
| 185 | static_assert(!has_type<std::common_reference<std::tuple<int, X2>, int, X2>>); |
| 186 | |
| 187 | struct A {}; |
| 188 | template <template<class> class TQual, template<class> class UQual> |
| 189 | struct std::basic_common_reference<A, std::tuple<B>, TQual, UQual> { |
| 190 | using type = tuple<UQual<B>>; |
| 191 | }; |
| 192 | |
| 193 | static_assert(std::is_same_v<std::common_reference_t<A, std::tuple<B>, std::tuple<D>>, std::tuple<B>>); |
| 194 | |
| 195 | |
| 196 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, int>>, |
| 197 | std::pair<int, int>>); |
| 198 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, long>, std::pair<long, int>>, |
| 199 | std::pair<long, long>>); |
| 200 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const int&>, std::pair<const int&, int>>, |
| 201 | std::pair<const int&, int>>); |
| 202 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, volatile int&>, std::pair<volatile int&, int>>, |
| 203 | std::pair<volatile int&, int>>); |
| 204 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int&, const volatile int&>, std::pair<const volatile int&, int>>, |
| 205 | std::pair<const volatile int&, int>>); |
| 206 | static_assert(!has_type<std::common_reference_t<std::pair<const int&, volatile int&>, |
| 207 | std::pair<volatile int&, const int&>>>); |
| 208 | |
| 209 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>); |
| 210 | static_assert(std::is_same_v<std::common_reference_t<std::pair<int, X2>, std::pair<int, Y2>>, std::pair<int, Z2>>); |
| 211 | static_assert(!has_type<std::common_reference<std::pair<int, const X2>, std::pair<float, const Z2>>>); |
| 212 | static_assert(!has_type<std::common_reference<std::pair<int, X2>, std::pair<float, Z2>>>); |
| 213 | static_assert(!has_type<std::common_reference<std::pair<int, X2>, int, X2>>); |
| 214 | #endif |
| 215 | |