[libcxx] r290627 - Implement P0435R1 - Resolving LWG issues for common_type

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 27 13:16:48 PST 2016


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>




More information about the cfe-commits mailing list