Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // A clone pointer template, that does not require the contained object to
- // have a clone method (but will use it if present).
- // (cc by) 2015 Daniel Nyström
- #include <functional>
- #include <utility>
- #include <iostream>
- #include <type_traits>
- template <typename T>
- struct has_clone
- {
- typedef char (& yes)[1];
- typedef char (& no)[2];
- template <typename C> static yes check(decltype(&C::clone));
- template <typename> static no check(...);
- static bool const value = sizeof(check<T>(0)) == sizeof(yes);
- };
- template<typename T> struct clone_ptr;
- template<typename T, typename U=T, typename ...Ts>
- clone_ptr<T> make_cloned( Ts&& ...ts );
- template<typename T>
- struct clone_ptr
- {
- typedef T element_type;
- clone_ptr() noexcept : ptr(nullptr) , cloner(nullptr) {}
- clone_ptr(clone_ptr&& other) noexcept
- : clone_ptr()
- {
- swap( other );
- }
- clone_ptr(const clone_ptr& other)
- : clone_ptr()
- {
- if( other )
- {
- cloner = other.cloner;
- ptr = (T*)cloner(other.ptr);
- }
- }
- void swap( clone_ptr& other ) noexcept
- {
- using std::swap;
- swap( ptr, other.ptr );
- swap( cloner, other.cloner );
- }
- clone_ptr& operator=( clone_ptr copy ) noexcept
- {
- swap(copy);
- return *this;
- }
- clone_ptr& operator=( std::nullptr_t )
- {
- clear();
- return *this;
- }
- T* operator->() { return ptr; }
- const T* operator->() const { return ptr; }
- T& operator*() { return *ptr; }
- const T& operator*() const { return *ptr; }
- explicit operator bool() const { return ptr != nullptr; }
- template<typename U, typename = typename std::enable_if< std::is_base_of<U,T>::value >::type >
- operator clone_ptr<U>()
- {
- return clone_ptr<U>( (U*)cloner(ptr), cloner );
- }
- bool operator<(const clone_ptr& other) const
- {
- bool have_self = ptr;
- bool have_othr = other.ptr;
- if( have_self && have_othr )
- return (*ptr) < (*other.ptr);
- else
- return have_self < have_othr;
- }
- bool operator>(const clone_ptr& other) const
- {
- bool have_self = ptr;
- bool have_othr = other.ptr;
- if( have_self && have_othr )
- return (*ptr) > (*other.ptr);
- else
- return have_self > have_othr;
- }
- bool operator==(const clone_ptr& other) const
- {
- bool have_self = ptr;
- bool have_othr = other.ptr;
- if( have_self && have_othr )
- return (*ptr) == (*other.ptr);
- else
- return have_self == have_othr;
- }
- bool operator!=(const clone_ptr& other) const { return ! ( other == *this ) ; }
- bool operator<=(const clone_ptr& other) const { return ! ( other < *this ) ; }
- bool operator>=(const clone_ptr& other) const { return ! ( other > *this ) ; }
- std::ostream& output( std::ostream& os, const char* null_ptr_msg = "<nullptr>" ) const
- {
- return ptr ? (os << *ptr) : (os << null_ptr_msg) ;
- }
- void clear() { delete ptr; ptr=nullptr; cloner=nullptr; }
- void reset() { clear(); }
- T* get() const { return ptr; }
- ~clone_ptr() { clear(); }
- private:
- template<typename T2=T, typename ...Ts>
- typename std::enable_if< ! has_clone<T2>::value , void >::type
- /*void*/ make( Ts&& ...ts )
- {
- clear();
- ptr = new T2( std::forward<Ts>(ts)... );
- cloner = [](void* p) -> void* { return new T2( * (T2*) p ); };
- }
- template<typename T2=T, typename ...Ts>
- typename std::enable_if< has_clone<T2>::value , void >::type
- /*void*/ make( Ts&& ...ts )
- {
- clear();
- ptr = new T2( std::forward<Ts>(ts)... );
- cloner = [](void* p) -> void* { return ((T2*)p)->clone(); };
- }
- typedef std::function<void*(void*)> Func;
- T* ptr;
- Func cloner;
- clone_ptr(T* ptr, Func cloner) : ptr(ptr), cloner(cloner) {}
- template<typename>
- friend struct clone_ptr;
- template<typename T2, typename U, typename ...Ts>
- friend clone_ptr<T2> make_cloned( Ts&& ...ts );
- };
- template<typename T, typename U, typename ...Ts>
- clone_ptr<T> make_cloned( Ts&& ...ts )
- {
- static_assert( std::is_base_of<T,U>::value || std::is_same<T,U>::value, "make_cloned<T,T2>: cant convert T to U" );
- clone_ptr<T> p;
- p.template make<U>( std::forward<Ts>(ts)... );
- return p;
- }
- template<typename T>
- std::ostream& operator<<(std::ostream& os, const clone_ptr<T>& p) { return p.output(os); }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement