// // copy_ptr.hpp // pointers // // Created by Sam Jaffe on 12/6/16. // #pragma once #include #include "pointer_fwd.hpp" #include "ptr_compare.hpp" namespace detail { template using clone_func = T* (T::*)() const; template class value_ptr_copy; template struct value_ptr_copy::value>::type> { T * Copy( T * ptr ) const { return ptr ? new T(*ptr) : nullptr; } }; #define POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION( fclone ) \ template \ struct value_ptr_copy::value \ && std::is_same, decltype(&T::fclone)>::value>::type> { \ T * Copy( T * ptr ) const { return ptr ? ptr->fclone() : nullptr; } \ } POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION( Clone ); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION( clone ); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION( Copy ); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION( copy ); } template class value_ptr : private detail::value_ptr_copy { public: using element_type = T; using pointer = element_type *; using reference = element_type &; value_ptr() noexcept : _ptr(nullptr) {} value_ptr(T * const & p) = delete; value_ptr(T * && p) noexcept(detail::is_nt_mc::value) : _ptr(std::move(p)) {} value_ptr(value_ptr const & other) : _ptr(detail::value_ptr_copy::Copy(other._ptr)) {} value_ptr(value_ptr && other) noexcept(noexcept(std::swap(_ptr, other._ptr))) : _ptr(nullptr) { std::swap(_ptr, other._ptr); } static value_ptr copy_of(T * const & p) { return detail::value_ptr_copy().Copy(p); } template explicit operator value_ptr() const { return Copy(_ptr); } ~value_ptr() { delete _ptr; } value_ptr & operator=(value_ptr const & other) { swap(_ptr, value_ptr{other}._ptr); return *this; } value_ptr & operator=(value_ptr && other) noexcept { swap(_ptr, other._ptr); return *this; } operator bool() const noexcept { return static_cast(_ptr); } pointer get() const noexcept { return _ptr; } pointer operator->() const noexcept { return get(); } reference operator*() const noexcept { return *get(); } private: static void swap( T * a, T * b ) { T * tmp = a; a = b; b = tmp; } T * _ptr; }; template value_ptr make_value(Args &&... args) { return value_ptr(new T(std::forward(args)...)); } POINTER_TEMPLATE_COMPARE( value_ptr )