Browse Source

Adding detail::get_ptr<P> to specialize chaining attribute pointers with smart pointers.
Making noexcept for operator*(), operator->(), and get() correct.

Samuel Jaffe 8 năm trước cách đây
mục cha
commit
a29e519e75
5 tập tin đã thay đổi với 29 bổ sung14 xóa
  1. 7 7
      const_propogating_ptr.hpp
  2. 4 4
      const_ptr.hpp
  3. 2 2
      maybe_null.hpp
  4. 1 1
      not_null.hpp
  5. 15 0
      pointer_fwd.hpp

+ 7 - 7
const_propogating_ptr.hpp

@@ -12,7 +12,7 @@
 #include "ptr_compare.hpp"
 
 template <typename P>
-class const_propogating_ptr {
+class const_propogating_ptr : private detail::get_ptr<P> {
 public:
   using element_type = typename std::pointer_traits<P>::element_type;
   using pointer = element_type  *;
@@ -48,13 +48,13 @@ public:
     return static_cast<bool>(_ptr);
   }
   
-  reference operator*() noexcept { return *_ptr; }
-  pointer get() noexcept { return std::addressof(operator*()); }
-  pointer operator->() noexcept { return get(); }
+  reference operator*() noexcept(noexcept(*_ptr)) { return *_ptr; }
+  pointer get() noexcept(noexcept(detail::get_ptr<P>::get(_ptr))) { return detail::get_ptr<P>::get(_ptr); }
+  pointer operator->() noexcept(noexcept(get())) { return get(); }
   
-  const_reference operator*() const noexcept { return *_ptr; }
-  const_pointer get() const noexcept { return std::addressof(operator*()); }
-  const_pointer operator->() const noexcept { return get(); }
+  const_reference operator*() const noexcept(noexcept(*_ptr)) { return *_ptr; }
+  const_pointer get() const noexcept(noexcept(detail::get_ptr<P>::get(_ptr))) { return detail::get_ptr<P>::get(_ptr); }
+  const_pointer operator->() const noexcept(noexcept(get())) { return get(); }
   
 private:
   P _ptr;

+ 4 - 4
const_ptr.hpp

@@ -12,7 +12,7 @@
 #include "ptr_compare.hpp"
 
 template <typename P>
-class const_ptr {
+class const_ptr : private detail::get_ptr<P> {
 public:
   using element_type = typename std::pointer_traits<P>::element_type;
   using pointer = element_type const *;
@@ -31,9 +31,9 @@ public:
     return static_cast<bool>(_ptr);
   }
 
-  reference operator*() const noexcept { return *_ptr; }
-  pointer get() const noexcept { return std::addressof(operator*()); }
-  pointer operator->() const noexcept { return get(); }
+  reference operator*() const noexcept(noexcept(*_ptr)) { return *_ptr; }
+  pointer get() const noexcept(noexcept(detail::get_ptr<P>::get(_ptr))) { return detail::get_ptr<P>::get(_ptr); }
+  pointer operator->() const noexcept(noexcept(get())) { return get(); }
 private:
   P _ptr;
 };

+ 2 - 2
maybe_null.hpp

@@ -26,7 +26,7 @@ template <typename P> class maybe_null<not_null<P>>; // not permitted
 #endif
 
 template <typename P>
-class maybe_null {
+class maybe_null : private detail::get_ptr<P> {
 public:
   using element_type = typename std::pointer_traits<P>::element_type;
   using pointer = element_type *;
@@ -49,7 +49,7 @@ public:
     return static_cast<bool>(_ptr);
   }
   
-  pointer get() const noexcept { return std::addressof(*_ptr); }
+  pointer get() const noexcept(noexcept(detail::get_ptr<P>::get(_ptr))) { return detail::get_ptr<P>::get(_ptr); }
   pointer operator->() const /*throw(unchecked_pointer_exception)*/ {
     return std::addressof(operator*());
   }

+ 1 - 1
not_null.hpp

@@ -44,7 +44,7 @@ public:
   
   operator bool() const noexcept { return true; }
   
-  pointer get() const noexcept { return std::addressof(operator*()); }
+  pointer get() const noexcept { return detail::get_ptr<P>().get(_ptr); }
   reference operator*() const noexcept { return *_ptr; }
   pointer operator->() const noexcept { return get(); }
   

+ 15 - 0
pointer_fwd.hpp

@@ -34,4 +34,19 @@ namespace detail {
   using is_nt_c = std::is_nothrow_constructible<P, Y>;
   template <typename P, typename Y>
   using is_nt_a = std::is_nothrow_assignable<P, Y>;
+  
+  template <typename P, typename = void>
+  struct get_ptr {
+    decltype(std::declval<P>().get()) get( P const & ptr ) const { return std::addressof(*ptr); }
+  };
+  
+  template <typename T>
+  struct get_ptr<T*> {
+    T* get( T* ptr ) const { return ptr; }
+  };
+
+  template <typename P>
+  struct get_ptr<P, typename std::enable_if<!std::is_void<decltype(std::declval<P>().get())>::value>::type> {
+    decltype(std::declval<P>().get()) get( P const & ptr ) const { return ptr.get(); }
+  };
 }