diff mbox

Make std::tuple_size<cv T> SFINAE-friendly (LWG 2770)

Message ID 20161115193319.GN3145@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Nov. 15, 2016, 7:33 p.m. UTC
This is needed to avoid problems with the new structured bindings
feature that landed in trunk yesterday.

As part of this patch I'm removing the docs for the DR 2742 and 2748
changes that I added earlier today. The manual doesn't need to track
changes against new features that only appear in trunk builds of GCC
and working drafts of the standard. DR 2770 should be documented
though, because it affects a C++11 feature that is in several GCC
releases.

	* doc/xml/manual/intro.xml: Document LWG 2770 status. Remove entries
	for 2742 and 2748.
	* doc/html/*: Regenerate.
	* include/std/utility (__tuple_size_cv_impl): New helper to safely
	detect tuple_size<T>::value, as per LWG 2770.
	(tuple_size<cv T>): Adjust partial specializations to derive from
	__tuple_size_cv_impl.
	* testsuite/20_util/tuple/cv_tuple_size.cc: Test SFINAE-friendliness.

Tested powerpc64le-linux, committed to trunk.
commit 6182fd1774f8129f127b213586807080fdc58d1b
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Nov 15 18:27:15 2016 +0000

    Make std::tuple_size<cv T> SFINAE-friendly (LWG 2770)
    
    	* doc/xml/manual/intro.xml: Document LWG 2770 status. Remove entries
    	for 2742 and 2748.
    	* doc/html/*: Regenerate.
    	* include/std/utility (__tuple_size_cv_impl): New helper to safely
    	detect tuple_size<T>::value, as per LWG 2770.
    	(tuple_size<cv T>): Adjust partial specializations to derive from
    	__tuple_size_cv_impl.
    	* testsuite/20_util/tuple/cv_tuple_size.cc: Test SFINAE-friendliness.
diff mbox

Patch

diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml
index 7f2586d..d23008a 100644
--- a/libstdc++-v3/doc/xml/manual/intro.xml
+++ b/libstdc++-v3/doc/xml/manual/intro.xml
@@ -1107,20 +1107,13 @@  requirements of the license of GCC.
     <listitem><para>Define the <code>value_compare</code> typedef.
     </para></listitem></varlistentry>
 
-    <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-defects.html#2742">2742</link>:
-       <emphasis>Inconsistent <code>string</code> interface taking <code>string_view</code>
+    <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-defects.html#2770">2770</link>:
+       <emphasis><code>tuple_size&lt;const T&gt;</code> specialization is not
+	 SFINAE compatible and breaks decomposition declarations
        </emphasis>
     </term>
-    <listitem><para>Add the new constructor and additionally constrain it
-      to avoid ambiguities with non-const <code>charT*</code>.
-    </para></listitem></varlistentry>
-
-    <varlistentry><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="../ext/lwg-defects.html#2748">2748</link>:
-       <emphasis>swappable traits for optionals
-       </emphasis>
-    </term>
-    <listitem><para>Disable the non-member <code>swap</code> overload when
-      the contained object is not swappable.
+    <listitem><para>Safely detect <code>tuple_size&lt;T&gt;::value</code> and
+      only use it if valid.
     </para></listitem></varlistentry>
 
   </variablelist>
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 2ca52fe..3982156 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -88,18 +88,24 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct tuple_size;
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2770. tuple_size<const T> specialization is not SFINAE compatible
+  template<typename _Tp, typename = void>
+    struct __tuple_size_cv_impl { };
+
+  template<typename _Tp>
+    struct __tuple_size_cv_impl<_Tp, __void_t<decltype(tuple_size<_Tp>::value)>>
+    : integral_constant<size_t, tuple_size<_Tp>::value> { };
+
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 2313. tuple_size should always derive from integral_constant<size_t, N>
   template<typename _Tp>
-    struct tuple_size<const _Tp>
-    : integral_constant<size_t, tuple_size<_Tp>::value> { };
+    struct tuple_size<const _Tp> : __tuple_size_cv_impl<_Tp> { };
 
   template<typename _Tp>
-    struct tuple_size<volatile _Tp>
-    : integral_constant<size_t, tuple_size<_Tp>::value> { };
+    struct tuple_size<volatile _Tp> : __tuple_size_cv_impl<_Tp> { };
 
   template<typename _Tp>
-    struct tuple_size<const volatile _Tp>
-    : integral_constant<size_t, tuple_size<_Tp>::value> { };
+    struct tuple_size<const volatile _Tp> : __tuple_size_cv_impl<_Tp> { };
 
   /// Gives the type of the ith element of a given tuple type.
   template<std::size_t __i, typename _Tp>
diff --git a/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size.cc b/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size.cc
index df5e0e9..c4a1e02 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/cv_tuple_size.cc
@@ -42,3 +42,13 @@  int main()
   test01();
   return 0;
 }
+
+// LWG DR 2770. tuple_size<const T> specialization is not SFINAE compatible
+template<typename T, typename = void>
+struct has_value : std::false_type { };
+
+template<typename T>
+struct has_value<T, std::__void_t<decltype(T::value)>> : std::true_type { };
+
+static_assert( !has_value<std::tuple_size<int>>::value, "" );
+static_assert( !has_value<std::tuple_size<const int>>::value, "" );