This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [v3 patch] Implement N4502 Standard Library Support for the C++ Detection Idiom


On 01/07/15 13:23 +0100, Jonathan Wakely wrote:
This adds the "detection idiom" API from N4502

http://open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf

I've added the low-level parts to <type_traits>, with public aliases
in <experimental/type_traits>, so that I can use them elsewhere in the
library.

For example this uses the new features to simplify pointer_traits.

These changes caused some new FAILs due to invalid uses of
pointer_traits that the standard says should be ill-formed but didn't
fail before. The patch fixes those tests.

Tested powerpc64le-linux, committed to trunk.


commit 9014ff9e72ef2d0048e1985d282341a3c37162ef
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jul 1 12:27:46 2015 +0100

    	* include/bits/ptr_traits.h (__ptrtr_elt_type, __ptrtr_diff_type,
    	__ptrtr_rebind, __ptrtr_not_void): Remove
    	(__get_first_arg, __replace_first_arg, __make_not_void): Define new
    	transformations.
    	(__detected_or_): New detection trait.
    	(pointer_traits): Use new traits.
    	* testsuite/20_util/pointer_traits/pointer_to.cc: Add rebind member.
    	* testsuite/20_util/pointer_traits/requirements/
    	explicit_instantiation.cc: Use valid arguments to pointer_traits.

diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h
index 9fd6bf8..84cc4da 100644
--- a/libstdc++-v3/include/bits/ptr_traits.h
+++ b/libstdc++-v3/include/bits/ptr_traits.h
@@ -32,114 +32,86 @@
 
 #if __cplusplus >= 201103L
 
-#include <type_traits> // For _GLIBCXX_HAS_NESTED_TYPE
+#include <type_traits>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-_GLIBCXX_HAS_NESTED_TYPE(element_type)
-_GLIBCXX_HAS_NESTED_TYPE(difference_type)
-
-  template<typename _Tp, bool = __has_element_type<_Tp>::value>
-    struct __ptrtr_elt_type;
+  class __undefined;
 
+  // Given Template<T, ...> return T, otherwise invalid.
   template<typename _Tp>
-    struct __ptrtr_elt_type<_Tp, true>
-    {
-      typedef typename _Tp::element_type __type;
-    };
-
-  template<template<typename, typename...> class _SomePtr, typename _Tp,
-            typename... _Args>
-    struct __ptrtr_elt_type<_SomePtr<_Tp, _Args...>, false>
-    {
-      typedef _Tp __type;
-    };
+    struct __get_first_arg
+    { using type = __undefined; };
 
-  template<typename _Tp, bool = __has_difference_type<_Tp>::value>
-    struct __ptrtr_diff_type
-    {
-      typedef typename _Tp::difference_type __type;
-    };
+  template<template<typename, typename...> class _Template, typename _Tp,
+           typename... _Types>
+    struct __get_first_arg<_Template<_Tp, _Types...>>
+    { using type = _Tp; };
 
   template<typename _Tp>
-    struct __ptrtr_diff_type<_Tp, false>
-    {
-      typedef ptrdiff_t __type;
-    };
-
-  template<typename _Ptr, typename _Up>
-    class __ptrtr_rebind_helper
-    {
-      template<typename _Ptr2, typename _Up2>
-	static constexpr true_type
-	_S_chk(typename _Ptr2::template rebind<_Up2>*);
-
-      template<typename, typename>
-	static constexpr false_type
-	_S_chk(...);
-
-    public:
-      using __type = decltype(_S_chk<_Ptr, _Up>(nullptr));
-    };
-
-  template<typename _Tp, typename _Up,
-           bool = __ptrtr_rebind_helper<_Tp, _Up>::__type::value>
-    struct __ptrtr_rebind;
+    using __get_first_arg_t = typename __get_first_arg<_Tp>::type;
 
+  // Given Template<T, ...> and U return Template<U, ...>, otherwise invalid.
   template<typename _Tp, typename _Up>
-    struct __ptrtr_rebind<_Tp, _Up, true>
-    {
-      typedef typename _Tp::template rebind<_Up> __type;
-    };
+    struct __replace_first_arg
+    { using type = __undefined; };
 
-  template<template<typename, typename...> class _SomePtr, typename _Up,
-            typename _Tp, typename... _Args>
-    struct __ptrtr_rebind<_SomePtr<_Tp, _Args...>, _Up, false>
-    {
-      typedef _SomePtr<_Up, _Args...> __type;
-    };
+  template<template<typename, typename...> class _Template, typename _Up,
+           typename _Tp, typename... _Types>
+    struct __replace_first_arg<_Template<_Tp, _Types...>, _Up>
+    { using type = _Template<_Up, _Types...>; };
 
-  template<typename _Tp, typename = typename remove_cv<_Tp>::type>
-    struct __ptrtr_not_void
-    {
-      typedef _Tp __type;
-    };
+  template<typename _Tp, typename _Up>
+    using __replace_first_arg_t = typename __replace_first_arg<_Tp, _Up>::type;
 
   template<typename _Tp>
-    struct __ptrtr_not_void<_Tp, void>
-    {
-      struct __type { };
-    };
-
-  template<typename _Ptr>
-    class __ptrtr_pointer_to
-    {
-      typedef typename __ptrtr_elt_type<_Ptr>::__type   __orig_type;
-      typedef typename __ptrtr_not_void<__orig_type>::__type __element_type;
-
-    public:
-      static _Ptr pointer_to(__element_type& __e)
-      { return _Ptr::pointer_to(__e); }
-    };
+    using __make_not_void
+      = typename conditional<is_void<_Tp>::value, __undefined, _Tp>::type;
 
   /**
    * @brief  Uniform interface to all pointer-like types
    * @ingroup pointer_abstractions
   */
   template<typename _Ptr>
-    struct pointer_traits : __ptrtr_pointer_to<_Ptr>
+    struct pointer_traits
     {
-      /// The pointer type
-      typedef _Ptr                                      pointer;
-      /// The type pointed to
-      typedef typename __ptrtr_elt_type<_Ptr>::__type   element_type;
-      /// Type used to represent the difference between two pointers
-      typedef typename __ptrtr_diff_type<_Ptr>::__type  difference_type;
+    private:
+      template<typename _Tp>
+	using __element_type = typename _Tp::element_type;
+
+      template<typename _Tp>
+	using __difference_type = typename _Tp::difference_type;
+
+      template<typename _Tp, typename _Up>
+	using __rebind = typename _Tp::template rebind<_Up>;
+
+    public:
+      /// The pointer type.
+      using pointer = _Ptr;
+
+      /// The type pointed to.
+      using element_type
+	= __detected_or_t_<__get_first_arg_t, __element_type, _Ptr>;
 
+      /// The type used to represent the difference between two pointers.
+      using difference_type
+	= __detected_or_t<ptrdiff_t, __difference_type, _Ptr>;
+
+      /// A pointer to a different type.
       template<typename _Up>
-        using rebind = typename __ptrtr_rebind<_Ptr, _Up>::__type;
+        using rebind
+	  = __detected_or_t_<__replace_first_arg_t, __rebind, _Ptr, _Up>;
+
+      static _Ptr
+      pointer_to(__make_not_void<element_type>& __e)
+      { return _Ptr::pointer_to(__e); }
+
+      static_assert(!is_same<element_type, __undefined>::value,
+	  "pointer type defines element_type or is like SomePointer<T, Args>");
+      static_assert(!is_same<rebind<element_type>, __undefined>::value,
+	  "pointer type defines rebind<U> or is like SomePointer<T, Args>");
     };
 
   /**
@@ -165,10 +137,14 @@ _GLIBCXX_HAS_NESTED_TYPE(difference_type)
        *  @return @c addressof(__r)
       */
       static pointer
-      pointer_to(typename __ptrtr_not_void<element_type>::__type& __r) noexcept
+      pointer_to(__make_not_void<element_type>& __r) noexcept
       { return std::addressof(__r); }
     };
 
+  /// Convenience alias for rebinding pointers.
+  template<typename _Ptr, typename _Tp>
+    using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>;
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/pointer_to.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/pointer_to.cc
index 843adbd..6782f79 100644
--- a/libstdc++-v3/testsuite/20_util/pointer_traits/pointer_to.cc
+++ b/libstdc++-v3/testsuite/20_util/pointer_traits/pointer_to.cc
@@ -26,6 +26,8 @@ struct Ptr
   typedef bool element_type;
   bool* value;
 
+  template<typename> using rebind = Ptr;
+
   static Ptr pointer_to(bool& b) { return Ptr{&b}; }
 };
 
diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/explicit_instantiation.cc
index f47bed0..d9c808f 100644
--- a/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/explicit_instantiation.cc
+++ b/libstdc++-v3/testsuite/20_util/pointer_traits/requirements/explicit_instantiation.cc
@@ -22,10 +22,25 @@
 
 #include <memory>
 
+template<typename T>
+struct P1
+{
+  using element_type = T;
+  using difference_type = long;
+  template<typename U> using rebind = P1<U>;
+  static P1 pointer_to(T&) { return {}; }
+};
+
+template<typename T>
+struct P2
+{
+  static P2 pointer_to(T&) { return {}; }
+};
+
 namespace std
 {
   typedef short test_type;
   template struct pointer_traits<test_type*>;
-  template struct pointer_traits<shared_ptr<test_type>>;
-  template struct pointer_traits<unique_ptr<test_type>>;
+  template struct pointer_traits<P1<test_type>>;
+  template struct pointer_traits<P2<test_type>>;
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]