Author: ericwf Date: Tue Dec 27 15:16:48 2016 New Revision: 290627 URL: http://llvm.org/viewvc/llvm-project?rev=290627&view=rev Log: Implement P0435R1 - Resolving LWG issues for common_type
Modified: libcxx/trunk/include/type_traits libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=290627&r1=290626&r2=290627&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Tue Dec 27 15:16:48 2016 @@ -1996,10 +1996,10 @@ struct _LIBCPP_TYPE_VIS_ONLY common_type // bullet 3 - sizeof...(Tp) == 2 template <class _Tp, class _Up, class = void> -struct __common_type2 {}; +struct __common_type2_imp {}; template <class _Tp, class _Up> -struct __common_type2<_Tp, _Up, +struct __common_type2_imp<_Tp, _Up, typename __void_t<decltype( true ? _VSTD::declval<_Tp>() : _VSTD::declval<_Up>() )>::type> @@ -2009,6 +2009,16 @@ struct __common_type2<_Tp, _Up, )>::type type; }; +template <class _Tp, class _Up, + class _DTp = typename decay<_Tp>::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 <class _Tp, class _Up> struct _LIBCPP_TYPE_VIS_ONLY common_type<_Tp, _Up> : __common_type2<_Tp, _Up> {}; Modified: libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp?rev=290627&r1=290626&r2=290627&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp Tue Dec 27 15:16:48 2016 @@ -12,6 +12,7 @@ // common_type #include <type_traits> +#include <memory> #include "test_macros.h" @@ -30,6 +31,14 @@ namespace std { typedef S<T> type; }; + + template <class T> + struct common_type< ::S<T>, T> { + typedef S<T> type; + }; + + template <> struct common_type< ::S<long>, long> {}; + template <> struct common_type<long, ::S<long> > {}; } #if TEST_STD_VER >= 11 @@ -48,6 +57,172 @@ constexpr bool no_common_type_imp(long) template <class ...Args> using no_common_type = std::integral_constant<bool, no_common_type_imp<Args...>(0)>; +template <class Tp> +using Decay = typename std::decay<Tp>::type; + +template <class ...Args> +using CommonType = typename std::common_type<Args...>::type; + +template <class T1, class T2> +struct TernaryOpImp { + static_assert(std::is_same<Decay<T1>, T1>::value, "must be same"); + static_assert(std::is_same<Decay<T2>, T2>::value, "must be same"); + using type = typename std::decay< + decltype(false ? std::declval<T1>() : std::declval<T2>()) + >::type; +}; + +template <class T1, class T2> +using TernaryOp = typename TernaryOpImp<T1, T2>::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<T0>. +void test_bullet_two() { + static_assert(std::is_same<CommonType<void>, void>::value, ""); + static_assert(std::is_same<CommonType<int>, int>::value, ""); + static_assert(std::is_same<CommonType<int const>, int>::value, ""); + static_assert(std::is_same<CommonType<int volatile[]>, int volatile*>::value, ""); + static_assert(std::is_same<CommonType<void(&)()>, void(*)()>::value, ""); +} + +template <class T, class U, class Expect> +void test_bullet_three_one_imp() { + using DT = Decay<T>; + using DU = Decay<U>; + static_assert(!std::is_same<T, DT>::value || !std::is_same<U, DU>::value, ""); + static_assert(std::is_same<CommonType<T, U>, Expect>::value, ""); + static_assert(std::is_same<CommonType<U, T>, Expect>::value, ""); + static_assert(std::is_same<CommonType<T, U>, CommonType<DT, DU>>::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<T1> and decay_t<T2>, respectively. +// (3.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() { + // Test that the user provided specialization of common_type is used after + // decaying T1. + { + using T1 = S<int> const; + using T2 = int; + test_bullet_three_one_imp<T1, T2, S<int> >(); + } + // Test a user provided specialization that does not provide a typedef. + { + using T1 = ::S<long> const; + using T2 = long; + static_assert(no_common_type<T1, T2>::value, ""); + static_assert(no_common_type<T2, T1>::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<CommonType<T1, T1>, Expect>::value, ""); + static_assert(std::is_same<CommonType<T1, T1>, CommonType<T1>>::value, ""); + } + { + using T1 = int const[]; + using Expect = int const*; + static_assert(std::is_same<CommonType<T1, T1>, Expect>::value, ""); + static_assert(std::is_same<CommonType<T1, T1>, CommonType<T1>>::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<T1> and decay_t<T2>, respectively. +// (3.3.1) +// -- If [...] +// (3.3.2) +// -- Otherwise, let C denote the same type, if any, as +// decay_t<decltype(false ? declval<D1>() : declval<D2>())> +void test_bullet_three_two() { + { + using T1 = int const*; + using T2 = int*; + using Expect = TernaryOp<T1, T2>; + static_assert(std::is_same<CommonType<T1, T2>, Expect>::value, ""); + static_assert(std::is_same<CommonType<T2, T1>, 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<T1, T2>::value, ""); + static_assert(no_common_type<T2, T1>::value, ""); + } + { + using T1 = int; + using T2 = X<int>; + static_assert(no_common_type<T1, T2>::value, ""); + static_assert(no_common_type<T2, T1>::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<CommonType<T1, T1>, Expect>::value, ""); + static_assert(std::is_same<CommonType<T1, T1>, CommonType<T1>>::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<T1, T2>. If there is +// such a type C, the member typedef-name type shall denote the +// same type, if any, as common_type_t<C, R...>. Otherwise, there shall be +// no member type. +void test_bullet_four() { + { // test that there is no ::type member + static_assert(no_common_type<int, E>::value, ""); + static_assert(no_common_type<int, int, E>::value, ""); + static_assert(no_common_type<int, int, E, int>::value, ""); + static_assert(no_common_type<int, int, int, E>::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<typename result_of<S(int)>::type, short>::value, "Error!"); +static_assert(is_same<typename result_of<S&(unsigned char, int&)>::type, double>::value, "Error!"); +static_assert(is_same<typename result_of<PF1()>::type, bool>::value, "Error!"); +static_assert(is_same<typename result_of<PMF(unique_ptr<S>, int)>::type, void>::value, "Error!"); +static_assert(is_same<typename result_of<PMD(S)>::type, char&&>::value, "Error!"); +static_assert(is_same<typename result_of<PMD(const S*)>::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<std::common_type<volatile void, void>::type, void>::value), ""); static_assert((std::is_same<std::common_type<const void, const void>::type, void>::value), ""); -#if TEST_STD_VER >= 11 - static_assert((no_common_type<void, int>::value), ""); - static_assert((no_common_type<int, void>::value), ""); - static_assert((no_common_type<int, E>::value), ""); - static_assert((no_common_type<int, int, E>::value), ""); - static_assert((no_common_type<int, int, E, int>::value), ""); - static_assert((no_common_type<int, int, int, E>::value), ""); - static_assert((no_common_type<int, X<int> >::value), ""); -#endif // TEST_STD_VER >= 11 - static_assert((std::is_same<std::common_type<int, S<int> >::type, S<int> >::value), ""); static_assert((std::is_same<std::common_type<int, S<int>, S<int> >::type, S<int> >::value), ""); static_assert((std::is_same<std::common_type<int, int, S<int> >::type, S<int> >::value), ""); + +#if TEST_STD_VER >= 11 + test_bullet_one(); + test_bullet_two(); + test_bullet_three_one(); + test_bullet_three_two(); + test_bullet_four(); +#endif } Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=290627&r1=290626&r2=290627&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Tue Dec 27 15:16:48 2016 @@ -128,7 +128,7 @@ <tr><td><a href="http://wg21.link/P0414R2">P0414R2</a></td><td>LWG</td><td>Merging shared_ptr changes from Library Fundamentals to C++17</td><td>Issaquah</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/P0418R2">P0418R2</a></td><td>LWG</td><td>Fail or succeed: there is no atomic lattice</td><td>Issaquah</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/P0426R1">P0426R1</a></td><td>LWG</td><td>Constexpr for <tt>std::char_traits</tt></td><td>Issaquah</td><td></td><td></td></tr> - <tr><td><a href="http://wg21.link/P0435R1">P0435R1</a></td><td>LWG</td><td>Resolving LWG Issues re <tt>common_type</tt></td><td>Issaquah</td><td></td><td></td></tr> + <tr><td><a href="http://wg21.link/P0435R1">P0435R1</a></td><td>LWG</td><td>Resolving LWG Issues re <tt>common_type</tt></td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr> <tr><td><a href="http://wg21.link/P0502R0">P0502R0</a></td><td>LWG</td><td>Throwing out of a parallel algorithm terminates - but how?</td><td>Issaquah</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/P0503R0">P0503R0</a></td><td>LWG</td><td>Correcting library usage of "literal type"</td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr> <tr><td><a href="http://wg21.link/P0504R0">P0504R0</a></td><td>LWG</td><td>Revisiting in-place tag types for any/optional/variant</td><td>Issaquah</td><td>Complete</td><td>4.0</td></tr> @@ -162,7 +162,7 @@ <tr><td><a href="http://wg21.link/LWG2400">2400</a></td><td><code>shared_ptr</code>'s <code>get_deleter()</code> should use <code>addressof()</code></td><td>Urbana</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2401">2401</a></td><td><code>std::function</code> needs more noexcept</td><td>Urbana</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2404">2404</a></td><td><code>mismatch()</code>'s complexity needs to be updated</td><td>Urbana</td><td>Complete</td></tr> - <tr><td><a href="http://wg21.link/LWG2408">2408</a></td><td>SFINAE-friendly <code>common_type</code> / <code>iterator_traits</code> is missing in C++14</td><td>Urbana</td><td><code>common_type</code> is waiting on <a href="http://wg21.link/LWG2465">LWG#2465</a></td></tr> + <tr><td><a href="http://wg21.link/LWG2408">2408</a></td><td>SFINAE-friendly <code>common_type</code> / <code>iterator_traits</code> is missing in C++14</td><td>Urbana</td><td>Complete</td></tr> <tr><td></td><td></td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2106">2106</td><td><code>move_iterator</code> wrapping iterators returning prvalues</td><td>Urbana</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2129">2129</td><td>User specializations of <code>std::initializer_list</code></td><td>Urbana</td><td>Complete</td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits