From 23f10ab4bfa7decba6c72a8b812ce822f3678406 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Sat, 27 Jan 2018 04:35:35 -0500 Subject: [PATCH] Update pointer_traits and to_address to reflect the design adopted for C++20 --- doc/pointer_traits.qbk | 56 +++--- include/boost/core/pointer_traits.hpp | 91 ++++----- test/Jamfile.v2 | 1 - test/pointer_traits_to_address_test.cpp | 131 ------------- test/to_address_test.cpp | 234 ++++++++++++++---------- 5 files changed, 219 insertions(+), 294 deletions(-) delete mode 100644 test/pointer_traits_to_address_test.cpp diff --git a/doc/pointer_traits.qbk b/doc/pointer_traits.qbk index 0da4fe6..bd8b3af 100644 --- a/doc/pointer_traits.qbk +++ b/doc/pointer_traits.qbk @@ -1,5 +1,5 @@ [/ -Copyright 2017 Glen Joseph Fernandes +Copyright 2017-2018 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -20,8 +20,10 @@ The header provides the class template `boost::pointer_traits` to facilitate use of pointer-like types. The C++11 standard library introduced `std::pointer_traits` along with an allocator model which supported pointer-like types in addition to plain raw pointers. -This implementation also supports C++98, and adds additional functionality -for obtaining raw pointers from pointers. +This implementation also supports C++98. + +It also provides the function template `boost::to_address` to obtain a raw +pointer from an object of any pointer-like type. [endsect] @@ -54,7 +56,6 @@ namespace boost { template using rebind = typename rebind_to::type; static pointer pointer_to(``['see below]`` v); - static element_type* to_address(const pointer& v) noexcept; }; template struct pointer_traits { @@ -66,11 +67,13 @@ namespace boost { template using rebind = typename rebind_to::type; static pointer pointer_to(``['see below]`` v) noexcept; - static element_type* to_address(pointer v) noexcept; }; template - typename pointer_traits::element_type* to_address(const T& v) noexcept; + constexpr T* to_address(T* v) noexcept; + + template + auto to_address(const T& v) noexcept; } ``` @@ -93,39 +96,44 @@ namespace boost { [section Member functions] -[variablelist pointer_traits -[[`static pointer pointer_to(`['see below] `v);`] +[variablelist +[[`static pointer pointer_traits::pointer_to(`['see below] `v);`] [[variablelist [[Remark] [If `element_type` is a void type, the type of `v` is unspecified; otherwise, it is `element_type&`.]] [[Returns] [A pointer to `v` obtained by calling `T::pointer_to(v)`.]]]]] -[[`static element_type* to_address(const pointer& v) noexcept;`] -[[variablelist -[[Requires] [`v` is not a null pointer.]] -[[Returns] -[A pointer of type `element_type*` that references the same location - as the argument.]]]]]] - -[variablelist pointer_traits -[[`static pointer pointer_to(`['see below] `v) noexcept;`] +[[`static pointer pointer_traits::pointer_to(`['see below] `v) noexcept;`] [[variablelist [[Remark] [If `element_type` is a void type, the type of `v` is unspecified; otherwise, it is `element_type&`.]] -[[Returns] [The result of `boost::addressof(v)`.]]]]] +[[Returns] [`addressof(v)`.]]]]]] + +[endsect] + +[section Optional members] + +[variablelist [[`static element_type* to_address(pointer v) noexcept;`] -[[variablelist [[Returns] [The value of `v`.]]]]]] +[[variablelist +[[Returns] +[A pointer of type `element_type*` that references the same location as the + argument `p`.]] +[[Note] [This function should be the inverse of `pointer_to`. If defined, it + customizes the behavior of the non-member function `to_address`.]]]]]] [endsect] [section Free functions] [variablelist -[[`template typename pointer_traits::element_type* - to_address(const T& v) noexcept;`] -[[variablelist [[Returns] [`boost::pointer_traits::to_address(v)`.]]]]]] +[[`template constexpr T* to_address(T* v) noexcept;`] +[[variablelist [[Returns] [`v`.]]]]] +[[`template auto to_address(const T& v) noexcept;`] +[[variablelist [[Returns] [`pointer_traits::to_address(v)` if that + expression is well-formed, otherwise `to_address(v.operator->())`.]]]]]] [endsect] @@ -133,8 +141,8 @@ namespace boost { [section Acknowledgments] -Glen Fernandes implemented `pointer_traits` with reviews and guidance from -Peter Dimov. +Glen Fernandes implemented `pointer_traits` and `to_address` with reviews and +guidance from Peter Dimov. [endsect] diff --git a/include/boost/core/pointer_traits.hpp b/include/boost/core/pointer_traits.hpp index 4ebd332..754728f 100644 --- a/include/boost/core/pointer_traits.hpp +++ b/include/boost/core/pointer_traits.hpp @@ -17,20 +17,6 @@ Distributed under the Boost Software License, Version 1.0. namespace boost { -template -struct pointer_traits; - -namespace detail { - -template -inline typename boost::pointer_traits::element_type* -ptr_to_address(const U& v) BOOST_NOEXCEPT -{ - return boost::pointer_traits::to_address(v); -} - -} /* detail */ - #if !defined(BOOST_NO_CXX11_POINTER_TRAITS) template struct pointer_traits @@ -39,10 +25,6 @@ struct pointer_traits struct rebind_to { typedef typename std::pointer_traits::template rebind type; }; - static typename std::pointer_traits::element_type* - to_address(const T& v) BOOST_NOEXCEPT { - return detail::ptr_to_address(v.operator->()); - } }; template @@ -52,9 +34,6 @@ struct pointer_traits struct rebind_to { typedef U* type; }; - static T* to_address(T* v) BOOST_NOEXCEPT { - return v; - } }; #else namespace detail { @@ -111,34 +90,34 @@ struct ptr_difference -struct ptr_rebind_to; +struct ptr_transform; #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template class T, class U, class... Args, class V> -struct ptr_rebind_to, V> { +struct ptr_transform, V> { typedef T type; }; #else template class T, class U, class V> -struct ptr_rebind_to, V> { +struct ptr_transform, V> { typedef T type; }; template class T, class U1, class U2, class V> -struct ptr_rebind_to, V> { +struct ptr_transform, V> { typedef T type; }; template class T, class U1, class U2, class U3, class V> -struct ptr_rebind_to, V> { +struct ptr_transform, V> { typedef T type; }; #endif template struct ptr_rebind { - typedef typename ptr_rebind_to::type type; + typedef typename ptr_transform::type type; }; #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) @@ -178,9 +157,6 @@ struct pointer_traits { pointer_to(typename detail::ptr_value::type& v) { return pointer::pointer_to(v); } - static element_type* to_address(const pointer& v) BOOST_NOEXCEPT { - return detail::ptr_to_address(v.operator->()); - } }; template @@ -200,26 +176,59 @@ struct pointer_traits { pointer_to(typename detail::ptr_value::type& v) BOOST_NOEXCEPT { return boost::addressof(v); } - static T* to_address(T* v) BOOST_NOEXCEPT { - return v; - } }; #endif template -inline typename pointer_traits::element_type* -to_address(const T& v) BOOST_NOEXCEPT -{ - return pointer_traits::to_address(v); -} - -template -inline T* +BOOST_CONSTEXPR inline T* to_address(T* v) BOOST_NOEXCEPT { return v; } +#if !defined(BOOST_NO_CXX11_SFINAE_EXPR) && \ + !defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) +namespace detail { + +template +inline T* +ptr_address(T* v, int) BOOST_NOEXCEPT +{ + return v; +} + +template +inline auto +ptr_address(const T& v, int) BOOST_NOEXCEPT +-> decltype(boost::pointer_traits::to_address(v)) +{ + return boost::pointer_traits::to_address(v); +} + +template +inline auto +ptr_address(const T& v, long) BOOST_NOEXCEPT +{ + return boost::detail::ptr_address(v.operator->(), 0); +} + +} /* detail */ + +template +inline auto +to_address(const T& v) BOOST_NOEXCEPT +{ + return boost::detail::ptr_address(v, 0); +} +#else +template +inline typename pointer_traits::element_type* +to_address(const T& v) BOOST_NOEXCEPT +{ + return boost::to_address(v.operator->()); +} +#endif + } /* boost */ #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7145555..66b96fc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -114,7 +114,6 @@ compile-fail scoped_enum_compile_fail_conv_to_int.cpp ; run underlying_type.cpp ; -run pointer_traits_to_address_test.cpp ; run pointer_traits_pointer_test.cpp ; run pointer_traits_element_type_test.cpp ; run pointer_traits_difference_type_test.cpp ; diff --git a/test/pointer_traits_to_address_test.cpp b/test/pointer_traits_to_address_test.cpp deleted file mode 100644 index aba0188..0000000 --- a/test/pointer_traits_to_address_test.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2017 Glen Joseph Fernandes -(glenjofe@gmail.com) - -Distributed under the Boost Software License, Version 1.0. -(http://www.boost.org/LICENSE_1_0.txt) -*/ -#include -#include - -template -class pointer { -public: - typedef typename boost::pointer_traits::element_type element_type; - pointer(T value) - : value_(value) { } - T operator->() const BOOST_NOEXCEPT { - return value_; - } -private: - T value_; -}; - -template -class special { -public: - special(T* value) - : value_(value) { } - T* get() const BOOST_NOEXCEPT { - return value_; - } -private: - T* value_; -}; - -namespace boost { - -template -struct pointer_traits > { - typedef special pointer; - typedef T element_type; - typedef std::ptrdiff_t difference_type; - template - struct rebind_to { - typedef special type; - }; -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template - using rebind = typename rebind_to::type; -#endif - template - static pointer pointer_to(U& v) BOOST_NOEXCEPT { - return pointer(&v); - } - static element_type* to_address(const pointer& v) BOOST_NOEXCEPT { - return v.get(); - } -}; - -} /* boost */ - -int main() -{ - int i = 0; - { - typedef int* type; - type p = &i; - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef void* type; - type p = &i; - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef const int* type; - type p = &i; - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::pointer_traits::to_address(p) == &i); - } - return boost::report_errors(); -} diff --git a/test/to_address_test.cpp b/test/to_address_test.cpp index 650d105..a5e280b 100644 --- a/test/to_address_test.cpp +++ b/test/to_address_test.cpp @@ -1,5 +1,5 @@ /* -Copyright 2017 Glen Joseph Fernandes +Copyright 2017-2018 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -9,123 +9,163 @@ Distributed under the Boost Software License, Version 1.0. #include template -class pointer { +class P1 { public: - typedef typename boost::pointer_traits::element_type element_type; - pointer(T value) - : value_(value) { } - T operator->() const BOOST_NOEXCEPT { - return value_; + explicit P1(T* p) + : p_(p) { } + T* operator->() const BOOST_NOEXCEPT { + return p_; } private: - T value_; + T* p_; }; template -class special { +class P2 { public: - special(T* value) - : value_(value) { } - T* get() const BOOST_NOEXCEPT { - return value_; + explicit P2(T* p) + : p_(p) { } + P1 operator->() const BOOST_NOEXCEPT { + return p_; } private: - T* value_; + P1 p_; +}; + +#if !defined(BOOST_NO_CXX11_SFINAE_EXPR) && \ + !defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) +template +class P3 { +public: + explicit P3(T* p) + : p_(p) { } + T* get() const BOOST_NOEXCEPT { + return p_; + } +private: + T* p_; }; namespace boost { template -struct pointer_traits > { - typedef special pointer; - typedef T element_type; - typedef std::ptrdiff_t difference_type; - template - struct rebind_to { - typedef special type; - }; -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template - using rebind = typename rebind_to::type; -#endif - template - static pointer pointer_to(U& v) BOOST_NOEXCEPT { - return pointer(&v); - } - static element_type* to_address(const pointer& v) BOOST_NOEXCEPT { - return v.get(); +struct pointer_traits > { + static T* to_address(const P3& p) BOOST_NOEXCEPT { + return p.get(); } }; } /* boost */ +template +class P4 { +public: + explicit P4(T* p) + : p_(p) { } + T* operator->() const BOOST_NOEXCEPT { + return 0; + } + T* get() const BOOST_NOEXCEPT { + return p_; + } +private: + int* p_; +}; + +namespace boost { + +template +struct pointer_traits > { + static T* to_address(const P4& p) BOOST_NOEXCEPT { + return p.get(); + } +}; + +} /* boost */ + +#if !defined(BOOST_NO_CXX11_POINTER_TRAITS) +template +class P5 { +public: + explicit P5(T* p) + : p_(p) { } + T* get() const BOOST_NOEXCEPT { + return p_; + } +private: + T* p_; +}; + +namespace std { + +template +struct pointer_traits > { + static T* to_address(const P5& p) BOOST_NOEXCEPT { + return p.get(); + } +}; + +} /* std */ + +template +class P6 { +public: + explicit P6(T* p) + : p_(p) { } + T* get() const BOOST_NOEXCEPT { + return p_; + } +private: + T* p_; +}; + +namespace boost { + +template +struct pointer_traits > { + static T* to_address(const P6& p) BOOST_NOEXCEPT { + return p.get(); + } +}; + +} /* boost */ + +namespace std { + +template +struct pointer_traits > { + static T* to_address(const P6& p) BOOST_NOEXCEPT { + return 0; + } +}; + +} /* std */ + +#endif +#endif + int main() { int i = 0; - { - typedef int* type; - type p = &i; - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef void* type; - type p = &i; - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef const int* type; - type p = &i; - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef special type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } - { - typedef pointer > type; - type p(&i); - BOOST_TEST(boost::to_address(p) == &i); - } + BOOST_TEST(boost::to_address(&i) == &i); + int* p = &i; + BOOST_TEST(boost::to_address(p) == &i); + P1 p1(&i); + BOOST_TEST(boost::to_address(p1) == &i); + P2 p2(&i); + BOOST_TEST(boost::to_address(p2) == &i); +#if !defined(BOOST_NO_CXX11_SFINAE_EXPR) && \ + !defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) + P3 p3(&i); + BOOST_TEST(boost::to_address(p3) == &i); + P4 p4(&i); + BOOST_TEST(boost::to_address(p4) == &i); +#if !defined(BOOST_NO_CXX11_POINTER_TRAITS) + P5 p5(&i); + BOOST_TEST(boost::to_address(p5) == &i); + P6 p6(&i); + BOOST_TEST(boost::to_address(p6) == &i); +#endif +#endif return boost::report_errors(); }