diff mbox

[v3] More work on std::tuple (and pair)

Message ID 4DE453CE.9050409@oracle.com
State New
Headers show

Commit Message

Paolo Carlini May 31, 2011, 2:34 a.m. UTC
Hi,

this improves the constraining in std::tuple (and in principle should 
render redundant the 1-element spec modulo c++/49225) and also tweak 
std::pair to use __and_ in order to minimize the number of 
instantiations. Plus smaller changes.

Tested x86_64-linux, committed to mainline.

Paolo.

//////////////////////////
2011-05-30  Paolo Carlini  <paolo.carlini@oracle.com>

	* include/std/type_traits (__or_, __and_): Add trivial definitions
	for a single element.
	* include/bits/stl_pair.h: Use __and_ in noexcept specs and
	constraints.
	(pair<>::pair(pair&&)): Define.
	(pair<>::pair(const pair<>&)): Constrain with is_convertible.
	(pair<>::pair(pair<>&&)): Likewise, remove noexcept.
	* include/std/tuple: Use __and_ in noexcept specs and constraints.
	(_Tuple_impl<>::_Tuple_impl(allocator_arg_t, const _Alloc&,
	_Tuple_impl&&)): Remove noexcept.
	(tuple<>::tuple(_UElements&&...), tuple(const tuple<_UElements...>&),
	tuple(tuple<_UElements...>&&), tuple(const pair<_U1, _U2>&),
	tuple(pair<_U1, _U2>&&)): Constrain with is_convertible.
	* testsuite/20_util/tuple/moveable2.cc: Use = delete.
	* testsuite/20_util/make_signed/requirements/typedefs_neg.cc:
	Adjust dg-error line numbers.
	* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc:
	Likewise.
	* testsuite/20_util/declval/requirements/1_neg.cc: Likewise.
	* testsuite/20_util/ratio/cons/cons_overflow_neg.cc: Likewise.
	* testsuite/20_util/weak_ptr/comparison/cmp_neg.cc: Likewise.
diff mbox

Patch

Index: include/std/tuple
===================================================================
--- include/std/tuple	(revision 174458)
+++ include/std/tuple	(working copy)
@@ -224,7 +224,7 @@ 
       : _Inherited(__tail...), _Base(__head) { }
 
       template<typename _UHead, typename... _UTail, typename = typename
-               std::enable_if<sizeof...(_Tail)==sizeof...(_UTail)>::type> 
+               enable_if<sizeof...(_Tail) == sizeof...(_UTail)>::type> 
         explicit
         _Tuple_impl(_UHead&& __head, _UTail&&... __tail)
 	: _Inherited(std::forward<_UTail>(__tail)...),
@@ -233,8 +233,8 @@ 
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
 
       _Tuple_impl(_Tuple_impl&& __in)
-      noexcept(std::is_nothrow_move_constructible<_Head>::value
-	       && std::is_nothrow_move_constructible<_Inherited>::value)
+      noexcept(__and_<is_nothrow_move_constructible<_Head>,
+	              is_nothrow_move_constructible<_Inherited>>::value)
       : _Inherited(std::move(__in._M_tail())), 
 	_Base(std::forward<_Head>(__in._M_head())) { }
 
@@ -254,13 +254,13 @@ 
 
       template<typename _Alloc>
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
-	    const _Head& __head, const _Tail&... __tail)
+		    const _Head& __head, const _Tail&... __tail)
 	: _Inherited(__tag, __a, __tail...),
           _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { }
 
       template<typename _Alloc, typename _UHead, typename... _UTail,
-               typename = typename std::enable_if<sizeof...(_Tail)
-		                                  ==sizeof...(_UTail)>::type>
+               typename = typename enable_if<sizeof...(_Tail)
+					     == sizeof...(_UTail)>::type>
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _UHead&& __head, _UTail&&... __tail)
 	: _Inherited(__tag, __a, std::forward<_UTail>(__tail)...),
@@ -276,8 +276,6 @@ 
       template<typename _Alloc>
 	_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
 	            _Tuple_impl&& __in)
-	noexcept(std::is_nothrow_move_constructible<_Head>::value
-		 && std::is_nothrow_move_constructible<_Inherited>::value)
 	: _Inherited(__tag, __a, std::move(__in._M_tail())), 
 	  _Base(__use_alloc<_Head, _Alloc, _Head>(__a),
 	        std::forward<_Head>(__in._M_head())) { }
@@ -305,8 +303,8 @@ 
 
       _Tuple_impl&
       operator=(_Tuple_impl&& __in)
-      noexcept(std::is_nothrow_move_assignable<_Head>::value
-	       && std::is_nothrow_move_assignable<_Inherited>::value)
+      noexcept(__and_<is_nothrow_move_assignable<_Head>,
+	              is_nothrow_move_assignable<_Inherited>>::value)
       {
 	_M_head() = std::forward<_Head>(__in._M_head());
 	_M_tail() = std::move(__in._M_tail());
@@ -359,9 +357,11 @@ 
       : _Inherited(__elements...) { }
 
       template<typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
-        explicit
+	enable_if<__and_<integral_constant<bool, sizeof...(_UElements)
+					   == sizeof...(_Elements)>,
+			 __and_<is_convertible<_UElements,
+					       _Elements>...>>::value>::type>
+	explicit
         tuple(_UElements&&... __elements)
 	: _Inherited(std::forward<_UElements>(__elements)...) {	}
 
@@ -369,15 +369,19 @@ 
       tuple(tuple&&) = default;
 
       template<typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	enable_if<__and_<integral_constant<bool, sizeof...(_UElements)
+					   == sizeof...(_Elements)>,
+			 __and_<is_convertible<const _UElements&,
+					       _Elements>...>>::value>::type>
         tuple(const tuple<_UElements...>& __in)
         : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
         { }
 
       template<typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	enable_if<__and_<integral_constant<bool, sizeof...(_UElements)
+					   == sizeof...(_Elements)>,
+			 __and_<is_convertible<_UElements,
+					       _Elements>...>>::value>::type>
         tuple(tuple<_UElements...>&& __in)
         : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
 
@@ -393,8 +397,8 @@ 
 	: _Inherited(__tag, __a, __elements...) { }
 
       template<typename _Alloc, typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	       enable_if<sizeof...(_UElements)
+			 == sizeof...(_Elements)>::type>
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      _UElements&&... __elements)
 	: _Inherited(__tag, __a, std::forward<_UElements>(__elements)...)
@@ -409,8 +413,8 @@ 
 	: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
 
       template<typename _Alloc, typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	       enable_if<sizeof...(_UElements)
+			 == sizeof...(_Elements)>::type>
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_UElements...>& __in)
 	: _Inherited(__tag, __a,
@@ -418,8 +422,8 @@ 
 	{ }
 
       template<typename _Alloc, typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	       enable_if<sizeof...(_UElements)
+			 == sizeof...(_Elements)>::type>
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      tuple<_UElements...>&& __in)
 	: _Inherited(__tag, __a,
@@ -435,15 +439,15 @@ 
 
       tuple&
       operator=(tuple&& __in)
-      noexcept(std::is_nothrow_move_assignable<_Inherited>::value)
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
       }
 
       template<typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	       enable_if<sizeof...(_UElements)
+			 == sizeof...(_Elements)>::type>
         tuple&
         operator=(const tuple<_UElements...>& __in)
         {
@@ -452,8 +456,8 @@ 
 	}
 
       template<typename... _UElements, typename = typename
-	       std::enable_if<sizeof...(_UElements)
-			      == sizeof...(_Elements)>::type>
+	       enable_if<sizeof...(_UElements)
+			 == sizeof...(_Elements)>::type>
         tuple&
         operator=(tuple<_UElements...>&& __in)
         {
@@ -488,7 +492,9 @@ 
       constexpr tuple(const _T1& __a1, const _T2& __a2)
       : _Inherited(__a1, __a2) { }
 
-      template<typename _U1, typename _U2>
+      template<typename _U1, typename _U2, typename = typename
+	       enable_if<__and_<is_convertible<_U1, _T1>,
+				is_convertible<_U2, _T2>>::value>::type>
         explicit
         tuple(_U1&& __a1, _U2&& __a2)
 	: _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { }
@@ -496,20 +502,28 @@ 
       constexpr tuple(const tuple&) = default;
       tuple(tuple&&) = default;
 
-      template<typename _U1, typename _U2>
+      template<typename _U1, typename _U2, typename = typename
+	enable_if<__and_<is_convertible<const _U1&, _T1>,
+			 is_convertible<const _U2&, _T2>>::value>::type>
         tuple(const tuple<_U1, _U2>& __in)
 	: _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
 
-      template<typename _U1, typename _U2>
+      template<typename _U1, typename _U2, typename = typename
+	       enable_if<__and_<is_convertible<_U1, _T1>,
+				is_convertible<_U2, _T2>>::value>::type>
         tuple(tuple<_U1, _U2>&& __in)
 	: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
 
-      template<typename _U1, typename _U2>
+      template<typename _U1, typename _U2, typename = typename
+	enable_if<__and_<is_convertible<const _U1&, _T1>,
+			 is_convertible<const _U2&, _T2>>::value>::type>
         tuple(const pair<_U1, _U2>& __in)
 	: _Inherited(__in.first, __in.second) { }
 
-      template<typename _U1, typename _U2>
-        tuple(pair<_U1, _U2>&& __in)
+      template<typename _U1, typename _U2, typename = typename
+	       enable_if<__and_<is_convertible<_U1, _T1>,
+				is_convertible<_U2, _T2>>::value>::type>
+         tuple(pair<_U1, _U2>&& __in)
 	: _Inherited(std::forward<_U1>(__in.first),
 		     std::forward<_U2>(__in.second)) { }
 
@@ -568,7 +582,7 @@ 
 
       tuple&
       operator=(tuple&& __in)
-      noexcept(std::is_nothrow_move_assignable<_Inherited>::value)
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
@@ -615,6 +629,9 @@ 
     };
 
   /// tuple (1-element).
+  // TODO: Should be simply removed when c++/49225 is fixed, worst case
+  //       together with a different way to constrain the constructors
+  //       of the primary template.
   template<typename _T1>
     class tuple<_T1> : public _Tuple_impl<0, _T1>
     {
@@ -629,7 +646,7 @@ 
       : _Inherited(__a1) { }
 
       template<typename _U1, typename = typename
-	       std::enable_if<std::is_convertible<_U1, _T1>::value>::type>
+	       enable_if<is_convertible<_U1, _T1>::value>::type>
         explicit
         tuple(_U1&& __a1)
 	: _Inherited(std::forward<_U1>(__a1)) { }
@@ -637,11 +654,13 @@ 
       constexpr tuple(const tuple&) = default;
       tuple(tuple&&) = default;
 
-      template<typename _U1>
+      template<typename _U1, typename = typename
+	       enable_if<is_convertible<const _U1&, _T1>::value>::type>
         tuple(const tuple<_U1>& __in)
 	: _Inherited(static_cast<const _Tuple_impl<0, _U1>&>(__in)) { }
 
-      template<typename _U1>
+      template<typename _U1, typename = typename
+	       enable_if<is_convertible<_U1, _T1>::value>::type>
         tuple(tuple<_U1>&& __in)
 	: _Inherited(static_cast<_Tuple_impl<0, _U1>&&>(__in)) { }
 
@@ -686,7 +705,7 @@ 
 
       tuple&
       operator=(tuple&& __in)
-      noexcept(std::is_nothrow_move_assignable<_Inherited>::value)
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
Index: include/std/type_traits
===================================================================
--- include/std/type_traits	(revision 174458)
+++ include/std/type_traits	(working copy)
@@ -59,9 +59,14 @@ 
   template<typename _Tp, _Tp>
     struct integral_constant;
 
-  template<typename, typename, typename...>
+  template<typename...>
     struct __or_;
 
+  template<typename _B1>
+    struct __or_<_B1>
+    : public _B1
+    { };
+
   template<typename _B1, typename _B2>
     struct __or_<_B1, _B2>
     : public conditional<_B1::value, _B1, _B2>::type
@@ -72,9 +77,14 @@ 
     : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type
     { };
 
-  template<typename, typename, typename...>
+  template<typename...>
     struct __and_;
 
+  template<typename _B1>
+    struct __and_<_B1>
+    : public _B1
+    { };
+
   template<typename _B1, typename _B2>
     struct __and_<_B1, _B2>
     : public conditional<_B1::value, _B2, _B1>::type
Index: include/bits/stl_pair.h
===================================================================
--- include/bits/stl_pair.h	(revision 174458)
+++ include/bits/stl_pair.h	(working copy)
@@ -105,37 +105,47 @@ 
       : first(__a), second(__b) { }
 
       /** There is also a templated copy ctor for the @c pair class itself.  */
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
       template<class _U1, class _U2>
-	_GLIBCXX_CONSTEXPR pair(const pair<_U1, _U2>& __p)
+	pair(const pair<_U1, _U2>& __p)
 	: first(__p.first), second(__p.second) { }
+#else
+      template<class _U1, class _U2, class = typename
+	       enable_if<__and_<is_convertible<const _U1&, _T1>,
+				is_convertible<const _U2&, _T2>>::value>::type>
+	constexpr pair(const pair<_U1, _U2>& __p)
+	: first(__p.first), second(__p.second) { }
 
-#ifdef __GXX_EXPERIMENTAL_CXX0X__
       constexpr pair(const pair&) = default;
 
-      // Implicit?!? Breaks containers!!!
-      // pair(pair&&) = default;
+      // XXX Defaulted?!? Breaks std::map!!!
+      pair(pair&& __p)
+      noexcept(__and_<is_nothrow_move_constructible<_T1>,
+	              is_nothrow_move_constructible<_T2>>::value)
+      : first(std::forward<first_type>(__p.first)),
+	second(std::forward<second_type>(__p.second)) { }
 
       // DR 811.
       template<class _U1, class = typename
-	       std::enable_if<std::is_convertible<_U1, _T1>::value>::type>
+	       enable_if<is_convertible<_U1, _T1>::value>::type>
 	pair(_U1&& __x, const _T2& __y)
 	: first(std::forward<_U1>(__x)), second(__y) { }
 
       template<class _U2, class = typename
-	       std::enable_if<std::is_convertible<_U2, _T2>::value>::type>
+	       enable_if<is_convertible<_U2, _T2>::value>::type>
 	pair(const _T1& __x, _U2&& __y)
 	: first(__x), second(std::forward<_U2>(__y)) { }
 
       template<class _U1, class _U2, class = typename
-	       std::enable_if<std::is_convertible<_U1, _T1>::value
-			      && std::is_convertible<_U2, _T2>::value>::type>
+	       enable_if<__and_<is_convertible<_U1, _T1>,
+				is_convertible<_U2, _T2>>::value>::type>
 	pair(_U1&& __x, _U2&& __y)
 	: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
 
-      template<class _U1, class _U2>
+      template<class _U1, class _U2, class = typename
+	       enable_if<__and_<is_convertible<_U1, _T1>,
+				is_convertible<_U2, _T2>>::value>::type>
 	pair(pair<_U1, _U2>&& __p)
-	noexcept(std::is_nothrow_constructible<_T1, _U1&&>::value
-		 && std::is_nothrow_constructible<_T2, _U2&&>::value)
 	: first(std::forward<_U1>(__p.first)),
 	  second(std::forward<_U2>(__p.second)) { }
 
@@ -155,11 +165,11 @@ 
 
       pair&
       operator=(pair&& __p)
-      noexcept(std::is_nothrow_move_assignable<_T1>::value
-	       && std::is_nothrow_move_assignable<_T2>::value)
+      noexcept(__and_<is_nothrow_move_assignable<_T1>,
+	              is_nothrow_move_assignable<_T2>>::value)
       {
-	first = std::move(__p.first);
-	second = std::move(__p.second);
+	first = std::forward<first_type>(__p.first);
+	second = std::forward<second_type>(__p.second);
 	return *this;
       }
 
@@ -176,8 +186,8 @@ 
 	pair&
 	operator=(pair<_U1, _U2>&& __p)
 	{
-	  first = std::move(__p.first);
-	  second = std::move(__p.second);
+	  first = std::forward<_U1>(__p.first);
+	  second = std::forward<_U2>(__p.second);
 	  return *this;
 	}
 
Index: testsuite/20_util/tuple/moveable2.cc
===================================================================
--- testsuite/20_util/tuple/moveable2.cc	(revision 174458)
+++ testsuite/20_util/tuple/moveable2.cc	(working copy)
@@ -1,6 +1,6 @@ 
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -17,7 +17,6 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-
 #include <tuple>
 #include <utility>
 
@@ -30,9 +29,8 @@ 
   MoveOnly& operator=(MoveOnly&&)
   { return *this; }
 
-private:
-  MoveOnly(MoveOnly const&); // = delete
-  MoveOnly& operator=(MoveOnly const&); // = delete
+  MoveOnly(MoveOnly const&) = delete;
+  MoveOnly& operator=(MoveOnly const&) = delete;
 };
 
 MoveOnly
Index: testsuite/20_util/make_signed/requirements/typedefs_neg.cc
===================================================================
--- testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(revision 174458)
+++ testsuite/20_util/make_signed/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@ 
 // { dg-error "instantiated from here" "" { target *-*-* } 40 }
 // { dg-error "instantiated from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1501 }
-// { dg-error "declaration of" "" { target *-*-* } 1465 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1511 }
+// { dg-error "declaration of" "" { target *-*-* } 1475 }
Index: testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
===================================================================
--- testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(revision 174458)
+++ testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc	(working copy)
@@ -48,5 +48,5 @@ 
 // { dg-error "instantiated from here" "" { target *-*-* } 40 }
 // { dg-error "instantiated from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1425 }
-// { dg-error "declaration of" "" { target *-*-* } 1389 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1435 }
+// { dg-error "declaration of" "" { target *-*-* } 1399 }
Index: testsuite/20_util/declval/requirements/1_neg.cc
===================================================================
--- testsuite/20_util/declval/requirements/1_neg.cc	(revision 174458)
+++ testsuite/20_util/declval/requirements/1_neg.cc	(working copy)
@@ -19,7 +19,7 @@ 
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 1715 }
+// { dg-error "static assertion failed" "" { target *-*-* } 1725 }
 
 #include <utility>
 
Index: testsuite/20_util/ratio/cons/cons_overflow_neg.cc
===================================================================
--- testsuite/20_util/ratio/cons/cons_overflow_neg.cc	(revision 174458)
+++ testsuite/20_util/ratio/cons/cons_overflow_neg.cc	(working copy)
@@ -51,4 +51,4 @@ 
 // { dg-error "instantiated from here" "" { target *-*-* } 46 }
 // { dg-error "denominator cannot be zero" "" { target *-*-* } 268 }
 // { dg-error "out of range" "" { target *-*-* } 269 }
-// { dg-error "overflow in constant expression" "" { target *-*-* } 99 }
+// { dg-error "overflow in constant expression" "" { target *-*-* } 109 }
Index: testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
===================================================================
--- testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(revision 174458)
+++ testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(working copy)
@@ -51,9 +51,9 @@ 
 // { dg-warning "note" "" { target *-*-* } 485 }
 // { dg-warning "note" "" { target *-*-* } 479 }
 // { dg-warning "note" "" { target *-*-* } 469 }
-// { dg-warning "note" "" { target *-*-* } 868 }
+// { dg-warning "note" "" { target *-*-* } 887 }
 // { dg-warning "note" "" { target *-*-* } 1056 }
 // { dg-warning "note" "" { target *-*-* } 1050 }
 // { dg-warning "note" "" { target *-*-* } 342 }
 // { dg-warning "note" "" { target *-*-* } 292 }
-// { dg-warning "note" "" { target *-*-* } 214 }
+// { dg-warning "note" "" { target *-*-* } 224 }