template <class _Tp> using make_unsigned_t = typename make_unsigned<_Tp>::type;
#endif
+#if _LIBCPP_STD_VER > 14
+template <class...> using void_t = void;
+#endif
+
+#if _LIBCPP_STD_VER > 17
+// Let COND_RES(X, Y) be:
+template <class _Tp, class _Up>
+using __cond_type = decltype(false ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>());
+
+template <class _Tp, class _Up, class = void>
+struct __common_type3 {};
+
+// sub-bullet 4 - "if COND_RES(CREF(D1), CREF(D2)) denotes a type..."
+template <class _Tp, class _Up>
+struct __common_type3<_Tp, _Up, void_t<__cond_type<const _Tp&, const _Up&>>>
+{
+ using type = remove_cvref_t<__cond_type<const _Tp&, const _Up&>>;
+};
+
+template <class _Tp, class _Up, class = void>
+struct __common_type2_imp : __common_type3<_Tp, _Up> {};
+#else
template <class _Tp, class _Up, class = void>
struct __common_type2_imp {};
+#endif
+// sub-bullet 3 - "if decay_t<decltype(false ? declval<D1>() : declval<D2>())> ..."
template <class _Tp, class _Up>
struct __common_type2_imp<_Tp, _Up,
typename __void_t<decltype(
// bullet 3 - sizeof...(Tp) == 2
+// sub-bullet 1 - "If is_same_v<T1, D1> is false or ..."
template <class _Tp, class _Up>
struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up>
: conditional<
#if _LIBCPP_STD_VER > 14
-template <class...> using void_t = void;
-
template <class... _Args>
struct conjunction : _And<_Args...> {};
template<class... _Args>
template <class T>
struct S { explicit S(T const&){} };
+template <class T>
+struct bad_reference_wrapper {
+ bad_reference_wrapper(T&);
+ bad_reference_wrapper(T&&) = delete;
+ operator T&() const;
+};
+
namespace std
{
template <typename T>
>::type type;
};
+// (4.1)
// -- If sizeof...(T) is zero, there shall be no member type.
void test_bullet_one() {
static_assert(no_common_type<>::value, "");
}
-// If sizeof...(T) is one, let T0 denote the sole type constituting the pack T.
-// The member typedef-name type shall denote the same type as decay_t<T0>.
+// (4.2)
+// -- If sizeof...(T) is one, let T0 denote the sole type constituting the pack
+// T. The member typedef-name type shall denote the same type, if any, as
+// common_type_t<T0, T0>; otherwise there shall be no member type.
void test_bullet_two() {
static_assert((std::is_same<std::common_type<void>::type, void>::value), "");
static_assert((std::is_same<std::common_type<int>::type, int>::value), "");
static_assert((std::is_same<typename std::common_type<T, U>::type, typename std::common_type<DT, DU>::type>::value), "");
}
-// (3.3)
+// (4.3)
// -- If sizeof...(T) is two, let the first and second types constituting T be
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
// as decay_t<T1> and decay_t<T2>, respectively.
-// (3.3.1)
+// (4.3.1)
// -- If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C
// denote the same type, if any, as common_type_t<D1, D2>.
void test_bullet_three_one() {
}
}
-// (3.3)
+// (4.3)
// -- If sizeof...(T) is two, let the first and second types constituting T be
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
// as decay_t<T1> and decay_t<T2>, respectively.
-// (3.3.1)
+// (4.3.1)
// -- If [...]
-// (3.3.2)
-// -- Otherwise, let C denote the same type, if any, as
+// (4.3.2)
+// -- [Note: [...]
+// (4.3.3)
+// -- Otherwise, if
// decay_t<decltype(false ? declval<D1>() : declval<D2>())>
-void test_bullet_three_two() {
+// denotes a type, let C denote that type.
+void test_bullet_three_three() {
{
typedef int const* T1;
typedef int* T2;
}
}
-// (3.4)
+// (4.3)
+// -- If sizeof...(T) is two, let the first and second types constituting T be
+// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
+// as decay_t<T1> and decay_t<T2>, respectively.
+// (4.3.1)
+// -- If [...]
+// (4.3.2)
+// -- [Note: [...]
+// (4.3.3)
+// -- Otherwise
+// (4.3.4)
+// -- Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, let C
+// denote the type decay_t<COND-RES(CREF(D1), CREF(D2))>.
+void test_bullet_three_four() {
+#if TEST_STD_VER >= 20
+ static_assert(std::is_same_v<std::common_type_t<int, bad_reference_wrapper<int>>, int>, "");
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<const bad_reference_wrapper<double>, double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<volatile bad_reference_wrapper<double>, double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<const volatile bad_reference_wrapper<double>, double>, double>, "");
+
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, const double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, volatile double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, const volatile double>, double>, "");
+
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>&, double>, double>, "");
+ static_assert(std::is_same_v<std::common_type_t<bad_reference_wrapper<double>, double&>, double>, "");
+#endif
+}
+
+// (4.4)
// -- If sizeof...(T) is greater than two, let T1, T2, and R, respectively,
// denote the first, second, and (pack of) remaining types constituting T.
// Let C denote the same type, if any, as common_type_t<T1, T2>. If there is
test_bullet_one();
test_bullet_two();
test_bullet_three_one();
- test_bullet_three_two();
+ test_bullet_three_three();
+ test_bullet_three_four();
test_bullet_four();
// P0548