diff --git a/include/type_traits b/include/type_traits index d970b7025..f6a016d0b 100644 --- a/include/type_traits +++ b/include/type_traits @@ -1996,10 +1996,10 @@ struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp> // bullet 3 - sizeof...(Tp) == 2 template -struct __common_type2 {}; +struct __common_type2_imp {}; template -struct __common_type2<_Tp, _Up, +struct __common_type2_imp<_Tp, _Up, typename __void_t() : _VSTD::declval<_Up>() )>::type> @@ -2009,6 +2009,16 @@ struct __common_type2<_Tp, _Up, )>::type type; }; +template ::type, + class _DUp = typename decay<_Up>::type> +using __common_type2 = + typename conditional< + is_same<_Tp, _DTp>::value && is_same<_Up, _DUp>::value, + __common_type2_imp<_Tp, _Up>, + common_type<_DTp, _DUp> + >::type; + template struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp, _Up> : __common_type2<_Tp, _Up> {}; diff --git a/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp index 763d80360..61523e487 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp @@ -12,6 +12,7 @@ // common_type #include +#include #include "test_macros.h" @@ -30,6 +31,14 @@ namespace std { typedef S type; }; + + template + struct common_type< ::S, T> { + typedef S type; + }; + + template <> struct common_type< ::S, long> {}; + template <> struct common_type > {}; } #if TEST_STD_VER >= 11 @@ -48,6 +57,172 @@ constexpr bool no_common_type_imp(long) { return true; } template using no_common_type = std::integral_constant(0)>; +template +using Decay = typename std::decay::type; + +template +using CommonType = typename std::common_type::type; + +template +struct TernaryOpImp { + static_assert(std::is_same, T1>::value, "must be same"); + static_assert(std::is_same, T2>::value, "must be same"); + using type = typename std::decay< + decltype(false ? std::declval() : std::declval()) + >::type; +}; + +template +using TernaryOp = typename TernaryOpImp::type; + +// -- 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. +void test_bullet_two() { + static_assert(std::is_same, void>::value, ""); + static_assert(std::is_same, int>::value, ""); + static_assert(std::is_same, int>::value, ""); + static_assert(std::is_same, int volatile*>::value, ""); + static_assert(std::is_same, void(*)()>::value, ""); +} + +template +void test_bullet_three_one_imp() { + using DT = Decay; + using DU = Decay; + static_assert(!std::is_same::value || !std::is_same::value, ""); + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, CommonType>::value, ""); +} + +// (3.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 and decay_t, respectively. +// (3.3.1) +// -- If is_same_v is false or is_same_v is false, let C +// denote the same type, if any, as common_type_t. +void test_bullet_three_one() { + // Test that the user provided specialization of common_type is used after + // decaying T1. + { + using T1 = S const; + using T2 = int; + test_bullet_three_one_imp >(); + } + // Test a user provided specialization that does not provide a typedef. + { + using T1 = ::S const; + using T2 = long; + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + } + // Test that the ternary operator is not applied when the types are the + // same. + { + using T1 = const void; + using Expect = void; + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, CommonType>::value, ""); + } + { + using T1 = int const[]; + using Expect = int const*; + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, CommonType>::value, ""); + } +} + +// (3.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 and decay_t, respectively. +// (3.3.1) +// -- If [...] +// (3.3.2) +// -- Otherwise, let C denote the same type, if any, as +// decay_t() : declval())> +void test_bullet_three_two() { + { + using T1 = int const*; + using T2 = int*; + using Expect = TernaryOp; + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, Expect>::value, ""); + } + // Test that there is no ::type member when the ternary op is ill-formed + { + using T1 = int; + using T2 = void; + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + } + { + using T1 = int; + using T2 = X; + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + } + // Test that the ternary operator is not applied when the types are the + // same. + { + using T1 = void; + using Expect = void; + static_assert(std::is_same, Expect>::value, ""); + static_assert(std::is_same, CommonType>::value, ""); + } +} + +// (3.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. If there is +// such a type C, the member typedef-name type shall denote the +// same type, if any, as common_type_t. Otherwise, there shall be +// no member type. +void test_bullet_four() { + { // test that there is no ::type member + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + static_assert(no_common_type::value, ""); + } +} + + +// The example code specified in Note B for common_type +namespace note_b_example { + +using PF1 = bool (&)(); +using PF2 = short (*)(long); + +struct S { + operator PF2() const; + double operator()(char, int&); + void fn(long) const; + char data; +}; + +using PMF = void (S::*)(long) const; +using PMD = char S::*; + +using std::is_same; +using std::result_of; +using std::unique_ptr; + +static_assert(is_same::type, short>::value, "Error!"); +static_assert(is_same::type, double>::value, "Error!"); +static_assert(is_same::type, bool>::value, "Error!"); +static_assert(is_same, int)>::type, void>::value, "Error!"); +static_assert(is_same::type, char&&>::value, "Error!"); +static_assert(is_same::type, const char&>::value, "Error!"); + +} // namespace note_b_example #endif // TEST_STD_VER >= 11 int main() @@ -98,17 +273,15 @@ int main() static_assert((std::is_same::type, void>::value), ""); static_assert((std::is_same::type, void>::value), ""); -#if TEST_STD_VER >= 11 - static_assert((no_common_type::value), ""); - static_assert((no_common_type::value), ""); - static_assert((no_common_type::value), ""); - static_assert((no_common_type::value), ""); - static_assert((no_common_type::value), ""); - static_assert((no_common_type::value), ""); - static_assert((no_common_type >::value), ""); -#endif // TEST_STD_VER >= 11 - static_assert((std::is_same >::type, S >::value), ""); static_assert((std::is_same, S >::type, S >::value), ""); static_assert((std::is_same >::type, S >::value), ""); + +#if TEST_STD_VER >= 11 + test_bullet_one(); + test_bullet_two(); + test_bullet_three_one(); + test_bullet_three_two(); + test_bullet_four(); +#endif } diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index bbdfff648..a4cefc096 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -128,7 +128,7 @@ P0414R2LWGMerging shared_ptr changes from Library Fundamentals to C++17Issaquah P0418R2LWGFail or succeed: there is no atomic latticeIssaquah P0426R1LWGConstexpr for std::char_traitsIssaquah - P0435R1LWGResolving LWG Issues re common_typeIssaquah + P0435R1LWGResolving LWG Issues re common_typeIssaquahComplete4.0 P0502R0LWGThrowing out of a parallel algorithm terminates - but how?Issaquah P0503R0LWGCorrecting library usage of "literal type"IssaquahComplete4.0 P0504R0LWGRevisiting in-place tag types for any/optional/variantIssaquahComplete4.0 @@ -162,7 +162,7 @@ 2400shared_ptr's get_deleter() should use addressof()UrbanaComplete 2401std::function needs more noexceptUrbanaComplete 2404mismatch()'s complexity needs to be updatedUrbanaComplete - 2408SFINAE-friendly common_type / iterator_traits is missing in C++14Urbanacommon_type is waiting on LWG#2465 + 2408SFINAE-friendly common_type / iterator_traits is missing in C++14UrbanaComplete 2106move_iterator wrapping iterators returning prvaluesUrbanaComplete 2129User specializations of std::initializer_listUrbanaComplete