diff --git a/doc/pointer_traits.qbk b/doc/pointer_traits.qbk index d0247fa..716d815 100644 --- a/doc/pointer_traits.qbk +++ b/doc/pointer_traits.qbk @@ -1,5 +1,5 @@ [/ -Copyright 2017-2018 Glen Joseph Fernandes +Copyright 2017-2021 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -47,68 +47,87 @@ void function(Allocator& a) ``` namespace boost { - template struct pointer_traits { + +template +struct pointer_traits { typedef T pointer; typedef ``['see below]`` element_type; typedef ``['see below]`` difference_type; - template struct rebind_to { typedef ``['see below]`` type; }; - template using rebind = typename rebind_to::type; + template + struct rebind_to { + typedef ``['see below]`` type; + }; - static pointer pointer_to(``['see below]`` v); - }; + template + using rebind = typename rebind_to::type; - template struct pointer_traits { + static pointer pointer_to(element_type& v); +}; + +template +struct pointer_traits { typedef T* pointer; typedef T element_type; typedef std::ptrdiff_t difference_type; - template struct rebind_to { typedef U* type; }; - template using rebind = typename rebind_to::type; + template + struct rebind_to { + typedef U* type; + }; + + template + using rebind = typename rebind_to::type; static pointer pointer_to(``['see below]`` v) noexcept; - }; +}; - template - constexpr T* to_address(T* v) noexcept; +template +constexpr T* to_address(T* v) noexcept; - template - auto to_address(const T& v) noexcept; -} +template +auto to_address(const T& v) noexcept; + +} // boost ``` +[section Overview] + +If the member type `element_type` is not defined, then all other members are +also not defined (`pointer_traits` is SFINAE-friendly). + +[endsect] + [section Member types] [variablelist [[`typedef` ['see below] `element_type;`] [`T::element_type` if such a type exists; otherwise `U` if `T` is a class template instantiation of the form `Pointer`, where `Args` is zero - or more type arguments; otherwise the specialization is ill-formed.]] + or more type arguments; otherwise the member is not defined.]] [[`typedef` ['see below] `difference_type;`] [`T::difference_type` if such a type exists; otherwise `std::ptrdiff_t`.]] [[`template struct rebind_to { typedef` ['see below] `type; };`] [`type` is `T::rebind` if such a type exists; otherwise, `Pointer` if `T` is a class template instantiation of the form `Pointer`, - where `Args` is zero or more type arguments; otherwise, the instantiation of - `rebind_to` is ill-formed.]]] + where `Args` is zero or more type arguments; otherwise, the member is not + defined.]]] [endsect] [section Member functions] [variablelist -[[`static pointer pointer_traits::pointer_to(`['see below] `v);`] +[[`static pointer pointer_traits::pointer_to(element_type& v);`] [[variablelist [[Remark] -[If `element_type` is a void type, the type of `v` is unspecified; otherwise, - it is `element_type&`.]] +[If `element_type` is a void type, this member is not defined.]] [[Returns] [A pointer to `v` obtained by calling `T::pointer_to(v)`.]]]]] -[[`static pointer pointer_traits::pointer_to(`['see below] `v) noexcept;`] +[[`static pointer pointer_traits::pointer_to(element_type& v) noexcept;`] [[variablelist [[Remark] -[If `element_type` is a void type, the type of `v` is unspecified; otherwise, - it is `element_type&`.]] +[If `element_type` is a void type, this member is not defined.]] [[Returns][`addressof(v)`.]]]]]] [endsect] diff --git a/include/boost/core/pointer_traits.hpp b/include/boost/core/pointer_traits.hpp index e66194d..2e78598 100644 --- a/include/boost/core/pointer_traits.hpp +++ b/include/boost/core/pointer_traits.hpp @@ -1,5 +1,5 @@ /* -Copyright 2017-2018 Glen Joseph Fernandes +Copyright 2017-2021 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -9,43 +9,23 @@ Distributed under the Boost Software License, Version 1.0. #define BOOST_CORE_POINTER_TRAITS_HPP #include -#if !defined(BOOST_NO_CXX11_POINTER_TRAITS) -#include -#else #include #include -#endif namespace boost { - -#if !defined(BOOST_NO_CXX11_POINTER_TRAITS) -template -struct pointer_traits - : std::pointer_traits { - template - struct rebind_to { - typedef typename std::pointer_traits::template rebind type; - }; -}; - -template -struct pointer_traits - : std::pointer_traits { - template - struct rebind_to { - typedef U* type; - }; -}; -#else namespace detail { +struct ptr_none { }; + template -struct ptr_void { +struct ptr_valid { typedef void type; }; -template -struct ptr_first; +template +struct ptr_first { + typedef ptr_none type; +}; #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template class T, class U, class... Args> @@ -75,7 +55,7 @@ struct ptr_element { }; template -struct ptr_element::type> { +struct ptr_element::type> { typedef typename T::element_type type; }; @@ -86,12 +66,12 @@ struct ptr_difference { template struct ptr_difference::type> { + typename ptr_valid::type> { typedef typename T::difference_type type; }; -template -struct ptr_transform; +template +struct ptr_transform { }; #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template class T, class U, class... Args, class V> @@ -117,68 +97,100 @@ struct ptr_transform, V> { #endif template -struct ptr_rebind { - typedef typename ptr_transform::type type; -}; +struct ptr_rebind + : ptr_transform { }; -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template struct ptr_rebind >::type> { + typename ptr_valid >::type> { typedef typename T::template rebind type; }; -#endif -template -struct ptr_value { - typedef T type; +template +struct ptr_void { + BOOST_STATIC_CONSTEXPR bool value = false; }; template<> -struct ptr_value { - typedef struct { } type; +struct ptr_void { + BOOST_STATIC_CONSTEXPR bool value = true; }; +template<> +struct ptr_void { + BOOST_STATIC_CONSTEXPR bool value = true; +}; + +template<> +struct ptr_void { + BOOST_STATIC_CONSTEXPR bool value = true; +}; + +template<> +struct ptr_void { + BOOST_STATIC_CONSTEXPR bool value = true; +}; + +template::value> +struct ptr_to { }; + +template +struct ptr_to { + static T pointer_to(E& v) { + return T::pointer_to(v); + } +}; + +template +struct ptr_to { + static T* pointer_to(T& v) BOOST_NOEXCEPT { + return boost::addressof(v); + } +}; + +template +struct ptr_traits + : ptr_to { + typedef T pointer; + typedef E element_type; + typedef typename ptr_difference::type difference_type; + + template + struct rebind_to + : ptr_rebind { }; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + template + using rebind = typename rebind_to::type; +#endif +}; + +template +struct ptr_traits { }; + } /* detail */ template -struct pointer_traits { - typedef T pointer; - typedef typename detail::ptr_element::type element_type; - typedef typename detail::ptr_difference::type difference_type; - template - struct rebind_to { - typedef typename detail::ptr_rebind::type type; - }; -#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) - template - using rebind = typename detail::ptr_rebind::type; -#endif - static pointer - pointer_to(typename detail::ptr_value::type& v) { - return pointer::pointer_to(v); - } -}; +struct pointer_traits + : detail::ptr_traits::type> { }; template -struct pointer_traits { +struct pointer_traits + : detail::ptr_to { typedef T* pointer; typedef T element_type; typedef std::ptrdiff_t difference_type; + template struct rebind_to { typedef U* type; }; + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template - using rebind = U*; + using rebind = typename rebind_to::type*; #endif - static T* - pointer_to(typename detail::ptr_value::type& v) BOOST_NOEXCEPT { - return boost::addressof(v); - } }; -#endif template BOOST_CONSTEXPR inline T* diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 58d46f5..9be78c0 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -189,6 +189,9 @@ run pointer_traits_element_type_test.cpp ; run pointer_traits_difference_type_test.cpp ; run pointer_traits_rebind_test.cpp ; run pointer_traits_pointer_to_test.cpp ; +run pointer_traits_sfinae_test.cpp ; +run pointer_traits_rebind_sfinae_test.cpp ; +run pointer_traits_pointer_to_sfinae_test.cpp ; run to_address_test.cpp ; run exchange_test.cpp ; diff --git a/test/pointer_traits_pointer_to_sfinae_test.cpp b/test/pointer_traits_pointer_to_sfinae_test.cpp new file mode 100644 index 0000000..30f6cec --- /dev/null +++ b/test/pointer_traits_pointer_to_sfinae_test.cpp @@ -0,0 +1,75 @@ +/* +Copyright 2021 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#if !defined(BOOST_NO_CXX11_DECLTYPE_N3276) || !defined(BOOST_MSVC) +#include +#include + +#if !defined(BOOST_NO_CXX11_DECLTYPE_N3276) +template +class has_pointer_to { + template + struct result { + char one; + char two; + }; + + template + static auto check(int) -> result; + + template + static char check(long); + +public: + static const bool value = sizeof(check(0)) != 1; +}; +#else +template +class has_pointer_to { + template + struct result { + char one; + char two; + }; + + template + static result check(int); + + template + static char check(long); + +public: + static const bool value = sizeof(check(0)) != 1; +}; +#endif + +struct P1 { }; + +struct P2 { + typedef int element_type; +}; + +struct P3 { + typedef void element_type; +}; + +int main() +{ + BOOST_TEST((!has_pointer_to >::value)); + BOOST_TEST(has_pointer_to >::value); + BOOST_TEST(!has_pointer_to >::value); + BOOST_TEST(has_pointer_to >::value); + BOOST_TEST(!has_pointer_to >::value); + return boost::report_errors(); +} +#else +int main() +{ + return 0; +} +#endif diff --git a/test/pointer_traits_rebind_sfinae_test.cpp b/test/pointer_traits_rebind_sfinae_test.cpp new file mode 100644 index 0000000..d6ad087 --- /dev/null +++ b/test/pointer_traits_rebind_sfinae_test.cpp @@ -0,0 +1,83 @@ +/* +Copyright 2021 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && \ + (!defined(BOOST_GCC) || (BOOST_GCC >= 40800)) && \ + (!defined(BOOST_MSVC) || (BOOST_MSVC >= 1900)) +#include +#include + +template +struct valid { + typedef void type; +}; + +#if !defined(BOOST_GCC) || (BOOST_GCC >= 50000) +template +struct has_rebind { + static const bool value = false; +}; + +template +struct has_rebind >::type> { + static const bool value = true; +}; +#else +template class T, class U> +using defer = T; + +template +using rebind = defer; + +template class = rebind, class = void> +struct has_rebind { + static const bool value = false; +}; + +template class R> +struct has_rebind >::type> { + static const bool value = true; +}; +#endif + +struct P1 { }; + +struct P2 { + typedef int element_type; +}; + +struct P3 { + typedef int element_type; + + template + struct rebind { }; +}; + +template +struct S { + typedef T element_type; +}; + +typedef S P4; + +int main() +{ + BOOST_TEST((!has_rebind, char>::value)); + BOOST_TEST((!has_rebind, char>::value)); + BOOST_TEST((has_rebind, char>::value)); + BOOST_TEST((has_rebind, char>::value)); + BOOST_TEST((has_rebind, char>::value)); + return boost::report_errors(); +} +#else +int main() +{ + return 0; +} +#endif diff --git a/test/pointer_traits_sfinae_test.cpp b/test/pointer_traits_sfinae_test.cpp new file mode 100644 index 0000000..a7ae787 --- /dev/null +++ b/test/pointer_traits_sfinae_test.cpp @@ -0,0 +1,101 @@ +/* +Copyright 2021 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 +struct valid { + typedef void type; +}; + +template +struct has_pointer { + static const bool value = false; +}; + +template +struct has_pointer::type> { + static const bool value = true; +}; + +template +struct has_element_type { + static const bool value = false; +}; + +template +struct has_element_type::type> { + static const bool value = true; +}; + +template +struct has_difference_type { + static const bool value = false; +}; + +template +struct has_difference_type::type> { + static const bool value = true; +}; + +template +struct has_rebind_to_type { + static const bool value = false; +}; + +template +struct has_rebind_to_type::type>::type> { + static const bool value = true; +}; + +struct P1 { }; + +struct P2 { + typedef int element_type; +}; + +struct P3 { + typedef int element_type; + + template + struct rebind { }; +}; + +template +struct S { + typedef T element_type; +}; + +typedef S P4; + +int main() +{ + BOOST_TEST(!has_pointer >::value); + BOOST_TEST(!has_element_type >::value); + BOOST_TEST(!has_difference_type >::value); + BOOST_TEST((!has_rebind_to_type, char>::value)); + BOOST_TEST(has_pointer >::value); + BOOST_TEST(has_element_type >::value); + BOOST_TEST(has_difference_type >::value); + BOOST_TEST((!has_rebind_to_type, char>::value)); + BOOST_TEST(has_pointer >::value); + BOOST_TEST(has_element_type >::value); + BOOST_TEST(has_difference_type >::value); + BOOST_TEST((has_rebind_to_type, char>::value)); + BOOST_TEST(has_pointer >::value); + BOOST_TEST(has_element_type >::value); + BOOST_TEST(has_difference_type >::value); + BOOST_TEST((has_rebind_to_type, char>::value)); + BOOST_TEST(has_pointer >::value); + BOOST_TEST(has_element_type >::value); + BOOST_TEST(has_difference_type >::value); + BOOST_TEST((has_rebind_to_type, char>::value)); + return boost::report_errors(); +} diff --git a/test/to_address_test.cpp b/test/to_address_test.cpp index 4c02384..4662e32 100644 --- a/test/to_address_test.cpp +++ b/test/to_address_test.cpp @@ -13,9 +13,11 @@ class P1 { public: explicit P1(T* p) : p_(p) { } + T* operator->() const BOOST_NOEXCEPT { return p_; } + private: T* p_; }; @@ -25,9 +27,11 @@ class P2 { public: explicit P2(T* p) : p_(p) { } + P1 operator->() const BOOST_NOEXCEPT { return p_; } + private: P1 p_; }; @@ -38,20 +42,24 @@ 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 > { static T* to_address(const P3& p) BOOST_NOEXCEPT { return p.get(); } }; + } /* boost */ template @@ -59,77 +67,29 @@ 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() @@ -147,12 +107,6 @@ int main() 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(); }