diff mbox

[v3,RFC] Implement LWG 2729 for tuple

Message ID CAFk2RUboRnmSwzU+h8LB-=2etHJxSGX=C0LM7acc_2+x=zOrfg@mail.gmail.com
State New
Headers show

Commit Message

Ville Voutilainen Aug. 31, 2016, 4:49 p.m. UTC
On 31 August 2016 at 18:40, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> Now tested with the full testsuite on Linux-PPC64, test in the patch
> amended slightly.
> New patch attached.

I added some more torture to the new test and re-indented it.

Comments

Jonathan Wakely Sept. 21, 2016, 9:43 a.m. UTC | #1
On 31/08/16 19:49 +0300, Ville Voutilainen wrote:
>@@ -338,6 +345,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       }
>     };
>
>+  template<typename...>
>+    struct __is_tuple_impl_trait_impl : false_type
>+  { };
>+
>+  template<std::size_t _Idx, typename... _Tp>
>+    struct __is_tuple_impl_trait_impl<_Tuple_impl<_Idx, _Tp...>> : true_type
>+  { };
>+
>+  template<typename _Tp>
>+    struct __is_tuple_impl_trait : public __is_tuple_impl_trait_impl<_Tp>
>+  { };

Please align the class bodies with the "struct" keyword here.

Otherwise OK for trunk, thanks.
diff mbox

Patch

diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index c06a040..9f43732 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -220,8 +220,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
 
       constexpr
-      _Tuple_impl(_Tuple_impl&& __in)
-      noexcept(__and_<is_nothrow_move_constructible<_Head>,
+      _Tuple_impl(typename conditional<
+		  __and_<is_move_constructible<_Head>,
+		         is_move_constructible<_Inherited>>::value,
+		  _Tuple_impl&&, __nonesuch&&>::type __in)
+	noexcept(__and_<is_nothrow_move_constructible<_Head>,
 	              is_nothrow_move_constructible<_Inherited>>::value)
       : _Inherited(std::move(_M_tail(__in))),
 	_Base(std::forward<_Head>(_M_head(__in))) { }
@@ -232,7 +235,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { }
 
       template<typename _UHead, typename... _UTails>
-        constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
+        constexpr _Tuple_impl(typename conditional<
+			      __and_<is_move_constructible<_Head>,
+			      is_move_constructible<_Inherited>>::value,
+			      _Tuple_impl<_Idx, _UHead, _UTails...>&&,
+			      __nonesuch&&>::type __in)
 	: _Inherited(std::move
 		     (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))),
 	  _Base(std::forward<_UHead>
@@ -338,6 +345,18 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
     };
 
+  template<typename...>
+    struct __is_tuple_impl_trait_impl : false_type
+  { };
+
+  template<std::size_t _Idx, typename... _Tp>
+    struct __is_tuple_impl_trait_impl<_Tuple_impl<_Idx, _Tp...>> : true_type
+  { };
+
+  template<typename _Tp>
+    struct __is_tuple_impl_trait : public __is_tuple_impl_trait_impl<_Tp>
+  { };
+
   // Basis case of inheritance recursion.
   template<std::size_t _Idx, typename _Head>
     struct _Tuple_impl<_Idx, _Head>
@@ -356,11 +375,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr _Tuple_impl()
       : _Base() { }
 
+      template<typename _Dummy=void,
+	       typename enable_if<is_constructible<_Base, const _Head&>::value,
+				  bool>::type=true>
       explicit
       constexpr _Tuple_impl(const _Head& __head)
       : _Base(__head) { }
 
-      template<typename _UHead>
+      template<typename _UHead,
+	       typename enable_if<__and_<is_constructible<_Base, _UHead&&>,
+					 __not_<__is_tuple_impl_trait<
+					   typename
+					     remove_reference<_UHead>::type>>
+					 >::value,
+				  bool>::type = true>
         explicit
         constexpr _Tuple_impl(_UHead&& __head)
 	: _Base(std::forward<_UHead>(__head)) { }
@@ -368,15 +396,21 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr _Tuple_impl(const _Tuple_impl&) = default;
 
       constexpr
-      _Tuple_impl(_Tuple_impl&& __in)
+      _Tuple_impl(typename conditional<
+		  is_move_constructible<_Head>::value,
+		  _Tuple_impl&&, __nonesuch&&>::type __in)
       noexcept(is_nothrow_move_constructible<_Head>::value)
       : _Base(std::forward<_Head>(_M_head(__in))) { }
 
-      template<typename _UHead>
+      template<typename _UHead,
+	       typename enable_if<!is_same<_Head, _UHead>::value,
+				  bool>::type = true>
         constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in)
 	: _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { }
 
-      template<typename _UHead>
+      template<typename _UHead,
+	       typename enable_if<!is_same<_Head, _UHead>::value,
+				  bool>::type = true>
         constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in)
 	: _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
 	{ }
@@ -832,14 +866,18 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{ }
 
       tuple&
-      operator=(const tuple& __in)
+      operator=(typename
+		conditional<__and_<is_copy_assignable<_Elements>...>::value,
+		const tuple&, const __nonesuch&>::type __in)
       {
 	static_cast<_Inherited&>(*this) = __in;
 	return *this;
       }
 
       tuple&
-      operator=(tuple&& __in)
+      operator=(typename
+		conditional<__and_<is_move_assignable<_Elements>...>::value,
+		tuple&&, __nonesuch&&>::type __in)
       noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
@@ -848,7 +886,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename... _UElements, typename = typename
 	       enable_if<sizeof...(_UElements)
-			 == sizeof...(_Elements)>::type>
+			 == sizeof...(_Elements)
+	       &&
+	       __and_<is_assignable<_Elements&,
+				    const _UElements&>...>::value>::type>
         tuple&
         operator=(const tuple<_UElements...>& __in)
         {
@@ -858,7 +899,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename... _UElements, typename = typename
 	       enable_if<sizeof...(_UElements)
-			 == sizeof...(_Elements)>::type>
+			 == sizeof...(_Elements)
+	       &&
+	       __and_<is_assignable<_Elements&,
+				    _UElements&&>...>::value>::type>
         tuple&
         operator=(tuple<_UElements...>&& __in)
         {
@@ -1189,14 +1233,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		     std::forward<_U2>(__in.second)) { }
 
       tuple&
-      operator=(const tuple& __in)
+      operator=(typename
+		conditional<__and_<is_copy_assignable<_T1>,
+		                   is_copy_assignable<_T2>>::value,
+		const tuple&, const __nonesuch&>::type __in)
       {
 	static_cast<_Inherited&>(*this) = __in;
 	return *this;
       }
 
       tuple&
-      operator=(tuple&& __in)
+      operator=(typename
+		conditional<__and_<is_move_assignable<_T1>,
+		                   is_move_assignable<_T2>>::value,
+		tuple&&, __nonesuch&&>::type __in)
       noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
@@ -1204,7 +1254,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
       template<typename _U1, typename _U2>
-        tuple&
+        typename
+          enable_if<__and_<is_assignable<_T1&, const _U1&>,
+			   is_assignable<_T2&, const _U2&>>::value,
+			   tuple&>::type
         operator=(const tuple<_U1, _U2>& __in)
         {
 	  static_cast<_Inherited&>(*this) = __in;
@@ -1212,7 +1265,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _U1, typename _U2>
-        tuple&
+        typename
+          enable_if<__and_<is_assignable<_T1&, _U1&&>,
+			   is_assignable<_T2&, _U2&&>>::value,
+			   tuple&>::type
         operator=(tuple<_U1, _U2>&& __in)
         {
 	  static_cast<_Inherited&>(*this) = std::move(__in);
@@ -1220,7 +1276,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _U1, typename _U2>
-        tuple&
+        typename
+          enable_if<__and_<is_assignable<_T1&, const _U1&>,
+			   is_assignable<_T2&, const _U2&>>::value,
+			   tuple&>::type
         operator=(const pair<_U1, _U2>& __in)
         {
 	  this->_M_head(*this) = __in.first;
@@ -1229,7 +1288,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _U1, typename _U2>
-        tuple&
+        typename
+          enable_if<__and_<is_assignable<_T1&, _U1&&>,
+			   is_assignable<_T2&, _U2&&>>::value,
+			   tuple&>::type
         operator=(pair<_U1, _U2>&& __in)
         {
 	  this->_M_head(*this) = std::forward<_U1>(__in.first);
diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
index 5bcf576..1c08d45 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc
@@ -17,7 +17,7 @@ 
 
 // { dg-options "-fno-show-column" }
 // { dg-do compile { target c++14 } }
-// { dg-error "in range" "" { target *-*-* } 1280 }
+// { dg-error "in range" "" { target *-*-* } 1342 }
 
 #include <tuple>
 
diff --git a/libstdc++-v3/testsuite/20_util/tuple/tuple_traits.cc b/libstdc++-v3/testsuite/20_util/tuple/tuple_traits.cc
new file mode 100644
index 0000000..b72f535
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/tuple_traits.cc
@@ -0,0 +1,244 @@ 
+// { dg-do compile { target c++11 } }
+
+// Copyright (C) 2016 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#include <memory>
+
+using namespace std;
+
+struct Poison
+{
+	Poison(Poison&&) = delete;
+};
+
+
+int main()
+{
+	static_assert(!is_copy_constructible<Poison>::value, "");
+	static_assert(!is_move_constructible<Poison>::value, "");
+	static_assert(!is_copy_assignable<Poison>::value, "");
+	static_assert(!is_move_assignable<Poison>::value, "");
+
+	static_assert(!is_copy_constructible<std::tuple<Poison>>::value, "");
+	static_assert(!is_move_constructible<std::tuple<Poison>>::value, "");
+	static_assert(!is_copy_assignable<std::tuple<Poison>>::value, "");
+	static_assert(!is_move_assignable<std::tuple<Poison>>::value, "");
+
+	static_assert(!is_copy_constructible<std::tuple<int, Poison>>::value,
+		      "");
+	static_assert(!is_move_constructible<std::tuple<int, Poison>>::value,
+		      "");
+	static_assert(!is_copy_assignable<std::tuple<int, Poison>>::value, "");
+	static_assert(!is_move_assignable<std::tuple<int, Poison>>::value, "");
+	static_assert(!is_constructible<std::tuple<int, Poison>&,
+		      std::tuple<char, Poison>&>::value, "");
+	static_assert(!is_assignable<std::tuple<int, Poison>&,
+		      std::tuple<char, Poison>&>::value, "");
+	static_assert(!is_constructible<std::tuple<int, Poison>&,
+		      std::tuple<char, Poison>>::value, "");
+	static_assert(!is_assignable<std::tuple<int, Poison>&,
+		      std::tuple<char, Poison>>::value, "");
+	static_assert(!is_constructible<std::tuple<int, Poison>&,
+		      std::pair<char, Poison>&>::value, "");
+	static_assert(!is_assignable<std::tuple<int, Poison>&,
+		      std::pair<char, Poison>&>::value, "");
+	static_assert(!is_constructible<std::tuple<int, Poison>&,
+		      std::pair<char, Poison>>::value, "");
+	static_assert(!is_assignable<std::tuple<int, Poison>&,
+		      std::pair<char, Poison>>::value, "");
+
+	static_assert(!is_copy_constructible<
+		      std::tuple<int, int, Poison>>::value, "");
+	static_assert(!is_move_constructible<
+		      std::tuple<int, int, Poison>>::value, "");
+	static_assert(!is_copy_assignable<
+		      std::tuple<int, int, Poison>>::value, "");
+	static_assert(!is_move_assignable<
+		      std::tuple<int, int, Poison>>::value, "");
+	static_assert(!is_constructible<
+		      std::tuple<int, int,Poison>&,
+		      std::tuple<int, char, Poison>&>::value, "");
+	static_assert(!is_assignable<
+		      std::tuple<int, int, Poison>&,
+		      std::tuple<int, char, Poison>&>::value, "");
+	static_assert(!is_constructible<
+		      std::tuple<int, int, Poison>&,
+		      std::tuple<int, char, Poison>>::value, "");
+	static_assert(!is_assignable<
+		      std::tuple<int, int, Poison>&,
+		      std::tuple<int, char, Poison>>::value, "");
+	static_assert(!is_constructible<
+		      std::tuple<int, int, Poison>&,
+		      std::pair<char, Poison>&>::value, "");
+	static_assert(!is_assignable<
+		      std::tuple<int, int, Poison>&,
+		      std::pair<char, Poison>&>::value, "");
+	static_assert(!is_constructible<
+		      std::tuple<int, int, Poison>&,
+		      std::pair<char, Poison>>::value, "");
+	static_assert(!is_assignable<
+		      std::tuple<int, int, Poison>&,
+		      std::pair<char, Poison>>::value, "");
+
+	static_assert(is_trivially_copy_constructible<tuple<int>>::value, "");
+	static_assert(!is_trivially_move_constructible<tuple<int>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<tuple<int>>::value, "");
+	static_assert(!is_trivially_move_assignable<tuple<int>>::value, "");
+
+	static_assert(is_copy_constructible<tuple<int>>::value, "");
+	static_assert(is_move_constructible<tuple<int>>::value, "");
+
+	static_assert(is_copy_assignable<tuple<int>>::value, "");
+	static_assert(is_move_assignable<tuple<int>>::value, "");
+
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<vector<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<vector<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<vector<int>>>::value, "");
+
+	static_assert(is_copy_constructible<tuple<vector<int>>>::value, "");
+	static_assert(is_move_constructible<tuple<vector<int>>>::value, "");
+
+	static_assert(is_copy_assignable<tuple<vector<int>>>::value, "");
+	static_assert(is_move_assignable<tuple<vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<unique_ptr<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<unique_ptr<int>>>::value, "");
+	static_assert(!is_copy_constructible<
+		      tuple<unique_ptr<int>>>::value, "");
+	static_assert(is_move_constructible<tuple<unique_ptr<int>>>::value, "");
+
+	static_assert(!is_copy_assignable<tuple<unique_ptr<int>>>::value, "");
+	static_assert(is_move_assignable<tuple<unique_ptr<int>>>::value, "");
+
+	static_assert(is_trivially_copy_constructible<
+		      tuple<int, int>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<int, int>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<int, int>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<int, int>>::value, "");
+
+	static_assert(is_copy_constructible<tuple<int, int>>::value, "");
+	static_assert(is_move_constructible<tuple<int, int>>::value, "");
+
+	static_assert(is_copy_assignable<tuple<int, int>>::value, "");
+	static_assert(is_move_assignable<tuple<int, int>>::value, "");
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<int, vector<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<int, vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<int, vector<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<int, vector<int>>>::value, "");
+
+	static_assert(is_copy_constructible<
+		      tuple<int, vector<int>>>::value, "");
+	static_assert(is_move_constructible<
+		      tuple<int, vector<int>>>::value, "");
+
+	static_assert(is_copy_assignable<tuple<int, vector<int>>>::value, "");
+	static_assert(is_move_assignable<tuple<int, vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<int, unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<int, unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_copy_constructible<
+		      tuple<int, unique_ptr<int>>>::value, "");
+	static_assert(is_move_constructible<
+		      tuple<int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_copy_assignable<
+		      tuple<int, unique_ptr<int>>>::value, "");
+	static_assert(is_move_assignable<
+		      tuple<int, unique_ptr<int>>>::value, "");
+
+	static_assert(is_copy_constructible<tuple<int, int, int>>::value, "");
+	static_assert(is_move_constructible<tuple<int, int, int>>::value, "");
+
+	static_assert(is_copy_assignable<tuple<int, int, int>>::value, "");
+	static_assert(is_move_assignable<tuple<int, int, int>>::value, "");
+
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<int, int, vector<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<int, int, vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<int, int, vector<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<int, int, vector<int>>>::value, "");
+
+	static_assert(is_copy_constructible<
+		      tuple<int, int, vector<int>>>::value, "");
+	static_assert(is_move_constructible<
+		      tuple<int, int, vector<int>>>::value, "");
+
+	static_assert(is_copy_assignable<
+		      tuple<int, int, vector<int>>>::value, "");
+	static_assert(is_move_assignable<
+		      tuple<int, int, vector<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_constructible<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_constructible<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_trivially_copy_assignable<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+	static_assert(!is_trivially_move_assignable<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_copy_constructible<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+	static_assert(is_move_constructible<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+
+	static_assert(!is_copy_assignable<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+	static_assert(is_move_assignable<
+		      tuple<int, int, unique_ptr<int>>>::value, "");
+}