stl_pair.h (__may_be_null_pointer_init): New.
authorDouglas Gregor <doug.gregor@gmail.com>
Sat, 18 Oct 2008 23:02:17 +0000 (23:02 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Sat, 18 Oct 2008 23:02:17 +0000 (23:02 +0000)
2008-10-18  Douglas Gregor  <doug.gregor@gmail.com>

* include/bits/stl_pair.h (__may_be_null_pointer_init): New.
(pair::pair): Eliminate the redundant pair(U1&&, U2&&) constructor.
Add lvalue pair<U1, U2> constructor to handle non-const pair lvalues.
Remove the old variadic constructor, and instead provide several
variadic constructors that avoid failing when attempting to
initialize a pointer from a null pointer constant.
* testsuite/20_util/pair/moveable.cc (test3): Add new tests with
initialization of pointers from the null pointer constant.

From-SVN: r141214

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_pair.h
libstdc++-v3/testsuite/20_util/pair/moveable.cc

index 18aa1778d5e5f9329f76c3879c842a55e69f61c1..cbbc0efe65253da09e3710fb8b6c8428a972a17c 100644 (file)
@@ -1,3 +1,14 @@
+2008-10-18  Douglas Gregor  <doug.gregor@gmail.com>
+
+       * include/bits/stl_pair.h (__may_be_null_pointer_init): New.
+       (pair::pair): Eliminate the redundant pair(U1&&, U2&&) constructor.
+       Add lvalue pair<U1, U2> constructor to handle non-const pair lvalues.
+       Remove the old variadic constructor, and instead provide several
+       variadic constructors that avoid failing when attempting to
+       initialize a pointer from a null pointer constant.
+       * testsuite/20_util/pair/moveable.cc (test3): Add new tests with
+       initialization of pointers from the null pointer constant.
+
 2008-10-17  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * include/bits/forward_list.tcc (forward_list<>::
index cf61b09945a0bbd8d548cb785e7fa4cb8569d851..c169275ece3f5c91436bab9a41ec252246f2190e 100644 (file)
 #include <bits/move.h> // for std::move / std::forward, std::decay, and
                        // std::swap
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#include <type_traits>
+#endif
+
 _GLIBCXX_BEGIN_NAMESPACE(std)
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+// A trait that determines whether the initialization of a T from
+// arguments of type Args could possibly be the initialization of a
+// pointer from a null pointer constant.
+template<typename, typename...>
+struct __may_be_null_pointer_init 
+  : public false_type { };
+
+template<typename _Tp, typename _Up>
+struct __may_be_null_pointer_init<_Tp*, _Up>  
+  : public integral_constant<bool,
+             (is_integral<typename remove_reference<_Up>::type>::value 
+              || is_enum<typename remove_reference<_Up>::type>::value)> 
+  { };
+
+template<typename _Class, typename _Tp, typename _Up>
+struct __may_be_null_pointer_init<_Tp _Class::*, _Up>  
+  : public integral_constant<bool,
+             (is_integral<typename remove_reference<_Up>::type>::value 
+              || is_enum<typename remove_reference<_Up>::type>::value)> 
+  { };
+#endif
+
   /// pair holds two objects of arbitrary type.
   template<class _T1, class _T2>
     struct pair
@@ -89,10 +116,12 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
       : first(__a), second(__b) { }
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
-      template<class _U1, class _U2>
-        pair(_U1&& __x, _U2&& __y)
-       : first(std::forward<_U1>(__x)),
-         second(std::forward<_U2>(__y)) { }
+      // Omitted the following constructor, which appears in the C++0x
+      // working paper but is redundant with the variadic constructors
+      // below.
+      //
+      //   template<class _U1, class _U2>
+      //     pair(_U1&& __x, _U2&& __y);
 
       pair(pair&& __p)
       : first(std::move(__p.first)),
@@ -111,12 +140,56 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
        : first(std::move(__p.first)),
          second(std::move(__p.second)) { }
 
-      // http://gcc.gnu.org/ml/libstdc++/2007-08/msg00052.html
-      template<class _U1, class _Arg0, class... _Args>
-        pair(_U1&& __x, _Arg0&& __arg0, _Args&&... __args)
+      // This constructor is required so that lvalue pairs don't get
+      // pushed to the variadic constructor below.
+      template<class _U1, class _U2>
+        pair(pair<_U1, _U2>& __p)
+          : first(const_cast<const pair<_U1, _U2>&>(__p).first),
+           second(const_cast<const pair<_U1, _U2>&>(__p).second) { }
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 811.  pair of pointers no longer works with literal 0
+
+      // Variadic constructor. The enable_if makes sure that we won't
+      // try to initialize a pointer from an integral type, which
+      // needs to be handled by a different constructor that will
+      // convert a null pointer constant to that pointer type. See
+      // library issue 767.
+      template<class _U1, class... _Args,
+        class _Checker 
+          = typename enable_if<
+                       (!__may_be_null_pointer_init<_T1, _U1>::value
+                        && !__may_be_null_pointer_init<_T2, _Args...>::value), 
+                     void>::type>
+        pair(_U1&& __x, _Args&&... __args)
+       : first(std::forward<_U1>(__x)),
+         second(std::forward<_Args>(__args)...) { }
+
+      // Variadic constructor. The enable_if makes sure that the
+      // second argument isn't going to try to initialize a pointer
+      // from an integral type. However, T1 may be a pointer whose
+      // argument was a null pointer constant.
+      template<class... _Args,
+        class _Checker 
+          = typename enable_if<
+                       !__may_be_null_pointer_init<_T2, _Args...>::value, 
+                     void>::type>
+        pair(const _T1& __x, _Args&&... __args)
+       : first(__x),
+         second(std::forward<_Args>(__args)...) { }
+
+      // Constructor typically used when T2 is a pointer and the
+      // second argument was a null pointer constant. The enable_if
+      // makes sure that the first argument isn't going to try to
+      // initialize a pointer from an integral type.
+      template<class _U1,
+        class _Checker 
+          = typename enable_if<
+                     !__may_be_null_pointer_init<_T1, _U1>::value,
+                     void>::type>
+        pair(_U1&& __x, const _T2& __y)
        : first(std::forward<_U1>(__x)),
-         second(std::forward<_Arg0>(__arg0),
-                std::forward<_Args>(__args)...) { }
+         second(__y) { }
 
       pair&
       operator=(pair&& __p)
index cd5de4162eb3608ebc4a70014701f1a1e1fb3283..4e5c53583cd6b4f13776dd30a3fc512aff96a314 100644 (file)
@@ -64,9 +64,54 @@ test2()
          r.second.size() == 2 && p.second.size() == 0);
 }
 
+struct X { 
+  explicit X(int, int) { }
+
+private:
+  X(const X&) = delete;
+};
+
+struct move_only {
+  move_only() { }
+  move_only(move_only&&) { }
+
+private:
+  move_only(const move_only&) = delete;
+};
+
+void
+test3()
+{
+  int *ip = 0;
+  int X::*mp = 0;
+  std::pair<int*, int*> p1(0, 0);
+  std::pair<int*, int*> p2(ip, 0);
+  std::pair<int*, int*> p3(0, ip);
+  std::pair<int*, int*> p4(ip, ip);
+
+  std::pair<int X::*, int*> p5(0, 0);
+  std::pair<int X::*, int X::*> p6(mp, 0);
+  std::pair<int X::*, int X::*> p7(0, mp);
+  std::pair<int X::*, int X::*> p8(mp, mp);
+
+  std::pair<int*, X> p9(0, 1, 2);
+  std::pair<int X::*, X> p10(0, 1, 2);
+  std::pair<int*, X> p11(ip, 1, 2);
+  std::pair<int X::*, X> p12(mp, 1, 2);
+
+  std::pair<int*, move_only> p13(0);
+  std::pair<int X::*, move_only> p14(0);
+
+  std::pair<int*, move_only> p15(0, move_only());
+  std::pair<int X::*, move_only> p16(0, move_only());
+  std::pair<move_only, int*> p17(move_only(), 0);
+  std::pair<move_only, int X::*> p18(move_only(), 0);
+}
+
 int 
 main() 
 {
   test1();
   test2();
+  test3();
 }