Patchwork [v3] constexpr tuple

login
register
mail settings
Submitter Benjamin Kosnik
Date Sept. 7, 2011, 12:23 a.m.
Message ID <20110906172309.2e1aafb9@shotwell>
Download mbox | patch
Permalink /patch/113684/
State New
Headers show

Comments

Benjamin Kosnik - Sept. 7, 2011, 12:23 a.m.
Here's the tuple additions for constexpr now that it's ok to return
this. 

I'm not quite sure what to do with the get, tie, tuple_cat functions
given the current signatures. Is tuple_cat now considered conforming?
If so, certain signatures can be constexpr. 

tested x86/linux

benjamin
Daniel Krügler - Sept. 7, 2011, 5:44 a.m.
2011/9/7 Benjamin Kosnik <bkoz@redhat.com>:
>
> Here's the tuple additions for constexpr now that it's ok to return
> this.

Btw.: I would have expected that you can make
__tuple_compare<>::__eq/__less also constexpr.

These are static functions, thus __tuple_compare
itself need not to be a literal type (Disclaimer: I did
not check all __tuple_compare specializations).

> Is tuple_cat now considered conforming?

No, see:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50159

> If so, certain signatures can be constexpr.

Yes.

- Daniel
Paolo Carlini - Sept. 8, 2011, 5:34 p.m.
On 09/07/2011 07:44 AM, Daniel Krügler wrote:
> Is tuple_cat now considered conforming?
> No, see:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50159
By the way, Daniel, I was considering giving that issue a try, if you 
have tips (or even more ;) about the implementation of the C++11 
conforming tuple_cat, I'm all ears...

Thanks,
Paolo.
Christopher Jefferson - Sept. 8, 2011, 6:24 p.m.
On 8 Sep 2011, at 18:34, Paolo Carlini wrote:

> On 09/07/2011 07:44 AM, Daniel Krügler wrote:
>> Is tuple_cat now considered conforming?
>> No, see:
>> 
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50159
> By the way, Daniel, I was considering giving that issue a try, if you have tips (or even more ;) about the implementation of the C++11 conforming tuple_cat, I'm all ears…

This might be totally insane, but I believe that:

tuple_cat(tuple_cat(A,B), C) always equivalent to tuple_cat(A,B,C);

Therefore, how close would something like (warning, not even compiled)

template<class _Tuple1, class _Tuple2, class… _Tuples>
auto 
tuple_cat(_Tuple1&& __t1, _Tuple2&& __t2, _Tuples&&… __tuples)
-> tuple_cat(tuple_cat(std::forward<_Tuple1>(__t1), std::forward<_Tuple2>(__t2)), 
			std::forward<_Tuples&&>(__tuples)…)
{ tuple_cat(tuple_cat(std::forward<_Tuple1>(__t1), std::forward<_Tuple2>(__t2)), 
		    std::forward<_Tuples&&>(__tuples)…); }

I imagine that first return type unfortunately isn't valid, but it shouldn't be hard to glue together the list of template arguments.

Chris
Marc Glisse - Sept. 8, 2011, 7:04 p.m.
On Thu, 8 Sep 2011, Christopher Jefferson wrote:

> This might be totally insane, but I believe that:
>
> tuple_cat(tuple_cat(A,B), C) always equivalent to tuple_cat(A,B,C);

That's a fine way to find the return type, but for code, doesn't it 
generate many copies? I think I'd forward_as_tuple and use some magic 
indices to extract everything at once.

Patch

2011-09-06  Benjamin Kosnik  <bkoz@redhat.com>

	* include/std/tuple (_Tuple_impl::_M_head, _M_tail): Mark constexpr.
	(tuple(tuple&&)): Same.
	(tuple(const tuple<_UElements...>& __in)): Same.
	(tuple(tuple<_UElements...>&& __in)): Same.
	(tuple_cat(const tuple<_TElements...>&, const tuple<_UElements...>&)):
	Same.
	(get): Same.
	* include/std/array: Consolidate array::data usage.
	* testsuite/23_containers/array/requirements/constexpr_functions.cc: 
	Remove extra include.
	* testsuite/20_util/tuple/creation_functions/constexpr.cc: New.
	* testsuite/20_util/tuple/cons/constexpr-2.cc: Add tests.
	* testsuite/20_util/tuple/cons/constexpr-3.cc: Same.
	* testsuite/20_util/weak_ptr/comparison/cmp_neg.cc: Adjust line numbers.

Index: include/std/tuple
===================================================================
--- include/std/tuple	(revision 178557)
+++ include/std/tuple	(working copy)
@@ -143,7 +143,7 @@ 
       _Head&       
       _M_head() noexcept { return *this; }
 
-      const _Head& 
+      constexpr const _Head& 
       _M_head() const noexcept { return *this; }
     };
 
@@ -189,7 +189,7 @@ 
       _Head&       
       _M_head() noexcept { return _M_head_impl; }
 
-      const _Head& 
+      constexpr const _Head& 
       _M_head() const noexcept { return _M_head_impl; }        
 
       _Head _M_head_impl; 
@@ -248,13 +248,13 @@ 
       _Head&            
       _M_head() noexcept { return _Base::_M_head(); }
 
-      const _Head&      
+      constexpr const _Head&      
       _M_head() const noexcept { return _Base::_M_head(); }
 
       _Inherited&       
       _M_tail() noexcept { return *this; }
 
-      const _Inherited& 
+      constexpr const _Inherited& 
       _M_tail() const noexcept { return *this; }
 
       constexpr _Tuple_impl()
@@ -280,7 +280,7 @@ 
 	_Base(std::forward<_Head>(__in._M_head())) { }
 
       template<typename... _UElements>
-        _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in)
+        constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in)
 	: _Inherited(__in._M_tail()), _Base(__in._M_head()) { }
 
       template<typename _UHead, typename... _UTails>
@@ -409,7 +409,7 @@ 
 
       constexpr tuple(const tuple&) = default;
 
-      tuple(tuple&&) = default;
+      constexpr tuple(tuple&&) = default; 
 
       template<typename... _UElements, typename = typename
 	enable_if<__and_<integral_constant<bool, sizeof...(_UElements)
@@ -417,7 +417,7 @@ 
 			 __all_convertible<__conv_types<const _UElements&...>,
 					   __conv_types<_Elements...>>
                          >::value>::type>
-        tuple(const tuple<_UElements...>& __in)
+        constexpr tuple(const tuple<_UElements...>& __in)
         : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
         { }
 
@@ -427,7 +427,7 @@ 
 			 __all_convertible<__conv_types<_UElements...>,
 					   __conv_types<_Elements...>>
 			 >::value>::type>
-        tuple(tuple<_UElements...>&& __in)
+        constexpr tuple(tuple<_UElements...>&& __in)
         : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
 
       // Allocator-extended constructors.
@@ -548,18 +548,18 @@ 
 
       constexpr tuple(const tuple&) = default;
 
-      tuple(tuple&&) = default;
+      constexpr tuple(tuple&&) = default;
 
       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)
+        constexpr tuple(const tuple<_U1, _U2>& __in)
 	: _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { }
 
       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)
+        constexpr tuple(tuple<_U1, _U2>&& __in)
 	: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
 
       template<typename _U1, typename _U2, typename = typename
@@ -571,7 +571,7 @@ 
       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)
+         constexpr tuple(pair<_U1, _U2>&& __in)
 	: _Inherited(std::forward<_U1>(__in.first),
 		     std::forward<_U2>(__in.second)) { }
 
@@ -752,7 +752,7 @@ 
     { return __t._M_head(); }
 
   template<std::size_t __i, typename _Head, typename... _Tail>
-    inline typename __add_c_ref<_Head>::type
+    inline constexpr typename __add_c_ref<_Head>::type
     __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
     { return __t._M_head(); }
 
@@ -767,7 +767,7 @@ 
     { return __get_helper<__i>(__t); }
 
   template<std::size_t __i, typename... _Elements>
-    inline typename __add_c_ref<
+    inline constexpr typename __add_c_ref<
                       typename tuple_element<__i, tuple<_Elements...>>::type
                     >::type
     get(const tuple<_Elements...>& __t) noexcept
@@ -789,13 +789,15 @@ 
   template<std::size_t __i, std::size_t __j, typename _Tp, typename _Up>
     struct __tuple_compare<0, __i, __j, _Tp, _Up>
     {
-      static bool __eq(const _Tp& __t, const _Up& __u)
+      static bool 
+      __eq(const _Tp& __t, const _Up& __u)
       {
 	return (get<__i>(__t) == get<__i>(__u) &&
 		__tuple_compare<0, __i + 1, __j, _Tp, _Up>::__eq(__t, __u));
       }
      
-      static bool __less(const _Tp& __t, const _Up& __u)
+      static bool 
+      __less(const _Tp& __t, const _Up& __u)
       {
 	return ((get<__i>(__t) < get<__i>(__u))
 		|| !(get<__i>(__u) < get<__i>(__t)) &&
@@ -806,11 +808,11 @@ 
   template<std::size_t __i, typename _Tp, typename _Up>
     struct __tuple_compare<0, __i, __i, _Tp, _Up>
     {
-      static bool __eq(const _Tp&, const _Up&)
-      { return true; }
+      static bool 
+      __eq(const _Tp&, const _Up&) { return true; }
      
-      static bool __less(const _Tp&, const _Up&)
-      { return false; }
+      static bool 
+      __less(const _Tp&, const _Up&) { return false; }
     };
 
   template<typename... _TElements, typename... _UElements>
@@ -899,7 +901,7 @@ 
     
   template<typename... _TElements, std::size_t... _TIdx,
 	   typename... _UElements, std::size_t... _UIdx> 
-    inline tuple<_TElements..., _UElements...> 
+    inline constexpr tuple<_TElements..., _UElements...> 
     __tuple_cat_helper(const tuple<_TElements...>& __t,
 		       const __index_holder<_TIdx...>&,
                        const tuple<_UElements...>& __u,
@@ -939,7 +941,7 @@ 
 	 std::forward<_UElements>(get<_UIdx>(__u))...); }
 
   template<typename... _TElements, typename... _UElements>
-    inline tuple<_TElements..., _UElements...> 
+    inline constexpr tuple<_TElements..., _UElements...> 
     tuple_cat(const tuple<_TElements...>& __t, const tuple<_UElements...>& __u)
     {
       return __tuple_cat_helper(__t, typename
@@ -1032,8 +1034,7 @@ 
   template<class _T1, class _T2>
     template<typename _Tp, typename... _Args>
       inline _Tp
-      pair<_T1, _T2>::
-      __cons(tuple<_Args...>&& __tuple)
+      pair<_T1, _T2>::__cons(tuple<_Args...>&& __tuple)
       {
 	typedef typename _Build_index_tuple<sizeof...(_Args)>::__type
 	  _Indexes;
@@ -1043,9 +1044,8 @@ 
   template<class _T1, class _T2>
     template<typename _Tp, typename... _Args, int... _Indexes>
       inline _Tp
-      pair<_T1, _T2>::
-      __do_cons(tuple<_Args...>&& __tuple,
-		const _Index_tuple<_Indexes...>&)
+      pair<_T1, _T2>::__do_cons(tuple<_Args...>&& __tuple,
+				const _Index_tuple<_Indexes...>&)
       { return _Tp(std::forward<_Args>(get<_Indexes>(__tuple))...); }
 
 _GLIBCXX_END_NAMESPACE_VERSION
Index: include/std/array
===================================================================
--- include/std/array	(revision 178557)
+++ include/std/array	(working copy)
@@ -61,8 +61,8 @@ 
     struct array
     {
       typedef _Tp 	    			      value_type;
-      typedef _Tp*                                    pointer;
-      typedef const _Tp*                              const_pointer;
+      typedef value_type*			      pointer;
+      typedef const value_type*                       const_pointer;
       typedef value_type&                   	      reference;
       typedef const value_type&             	      const_reference;
       typedef value_type*          		      iterator;
@@ -90,19 +90,19 @@ 
       // Iterators.
       iterator
       begin() noexcept
-      { return iterator(std::__addressof(_M_instance[0])); }
+      { return iterator(data()); }
 
       const_iterator
       begin() const noexcept
-      { return const_iterator(std::__addressof(_M_instance[0])); }
+      { return const_iterator(data()); }
 
       iterator
       end() noexcept
-      { return iterator(std::__addressof(_M_instance[_Nm])); }
+      { return iterator(data() + _Nm); }
 
       const_iterator
       end() const noexcept
-      { return const_iterator(std::__addressof(_M_instance[_Nm])); }
+      { return const_iterator(data() + _Nm); }
 
       reverse_iterator 
       rbegin() noexcept
@@ -195,11 +195,11 @@ 
       back() const
       { return _Nm ? *(end() - 1) : *end(); }
 
-      _Tp*
+      pointer
       data() noexcept
       { return std::__addressof(_M_instance[0]); }
 
-      const _Tp*
+      const_pointer
       data() const noexcept
       { return std::__addressof(_M_instance[0]); }
     };
Index: testsuite/23_containers/array/requirements/constexpr_functions.cc
===================================================================
--- testsuite/23_containers/array/requirements/constexpr_functions.cc	(revision 178557)
+++ testsuite/23_containers/array/requirements/constexpr_functions.cc	(working copy)
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2010 Free Software Foundation, Inc.
+// Copyright (C) 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
@@ -19,7 +19,6 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include <array>
-#include <testsuite_common_types.h>
 
 namespace __gnu_test
 {
Index: testsuite/20_util/tuple/creation_functions/constexpr.cc
===================================================================
--- testsuite/20_util/tuple/creation_functions/constexpr.cc	(revision 0)
+++ testsuite/20_util/tuple/creation_functions/constexpr.cc	(revision 0)
@@ -0,0 +1,90 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 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
+// 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/>.
+
+
+// NOTE: This makes use of the fact that we know how moveable
+// is implemented on pair, and also vector. If the implementation
+// changes this test may begin to fail.
+
+#include <tuple>
+
+bool test __attribute__((unused)) = true;
+
+
+// make_tuple
+#if 0
+void
+test_make_tuple()
+{
+  {
+    typedef std::tuple<int, float> tuple_type;
+    constexpr tuple_type p1 = std::make_tuple(22, 22.222);
+  }
+
+  {
+    typedef std::tuple<int, float, int> tuple_type;
+    constexpr tuple_type p1 = std::make_tuple(22, 22.222, 77799);
+  }
+}
+#endif
+
+// get
+void
+test_get()
+{
+  {
+    typedef std::tuple<int, float> tuple_type;
+    constexpr tuple_type t1 { 55, 77.77 };
+    constexpr auto var = std::get<1>(t1);
+  }
+
+  {
+    typedef std::tuple<int, float, int> tuple_type;
+    constexpr tuple_type t1 { 55, 77.77, 99 };
+    constexpr auto var = std::get<2>(t1);
+  }
+}
+
+// tuple_cat
+void
+test_tuple_cat()
+{
+  typedef std::tuple<int, float> 	tuple_type1;
+  typedef std::tuple<int, int, float> tuple_type2;
+
+  constexpr tuple_type1 t1 { 55, 77.77 };
+  constexpr tuple_type2 t2 { 55, 99, 77.77 };
+  constexpr auto cat1 = std::tuple_cat(t1, t2);
+}
+
+
+int
+main()
+{
+#if 0
+  test_make_tuple();
+#endif
+
+  test_get();
+
+  test_tuple_cat();
+
+  return 0;
+}
Index: testsuite/20_util/tuple/cons/constexpr-2.cc
===================================================================
--- testsuite/20_util/tuple/cons/constexpr-2.cc	(revision 178557)
+++ testsuite/20_util/tuple/cons/constexpr-2.cc	(working copy)
@@ -56,8 +56,8 @@ 
   test2.operator()<tuple_type, std::pair<short, short>>();
 
   // 07: different-tuple-type conversion constructor
-  // test2.operator()<tuple_type, std::tuple<short, short>>();
-  // test2.operator()<std::tuple<short, short>, tuple_type>();
+  test2.operator()<tuple_type, std::tuple<short, short>>();
+  test2.operator()<std::tuple<short, short>, tuple_type>();
 
   return 0;
 }
Index: testsuite/20_util/tuple/cons/constexpr-3.cc
===================================================================
--- testsuite/20_util/tuple/cons/constexpr-3.cc	(revision 178557)
+++ testsuite/20_util/tuple/cons/constexpr-3.cc	(working copy)
@@ -53,8 +53,8 @@ 
   constexpr tuple_type t8(i5, i6, i7);
 
   // 06: different-tuple-type conversion constructor
-  // test2.operator()<tuple_type, std::tuple<short, short, short>>();
-  // test2.operator()<std::tuple<short, short, short>, tuple_type>();
+  test2.operator()<tuple_type, std::tuple<short, short, short>>();
+  test2.operator()<std::tuple<short, short, short>, tuple_type>();
 
   return 0;
 }
Index: testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
===================================================================
--- testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(revision 178557)
+++ testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(working copy)
@@ -51,7 +51,7 @@ 
 // { dg-warning "note" "" { target *-*-* } 485 }
 // { dg-warning "note" "" { target *-*-* } 479 }
 // { dg-warning "note" "" { target *-*-* } 468 }
-// { dg-warning "note" "" { target *-*-* } 829 }
+// { dg-warning "note" "" { target *-*-* } 831 }
 // { dg-warning "note" "" { target *-*-* } 1056 }
 // { dg-warning "note" "" { target *-*-* } 1050 }
 // { dg-warning "note" "" { target *-*-* } 342 }