좋은 마법의 주문을 바로 잡아서 좋은 C++ 컴파일러가 코드에 만족하고, 의미에 만족했다면, 나는 (매우 베어 본) value_ptr
을 사본과 의미 이동. 기억해야 할 중요한 것은 make_value<Derived>
을 사용하여 올바른 복사 기능을 선택하는 것입니다. 그렇지 않으면 사본이 개체를 잘라냅니다. 실제로 슬라이싱을 견딜 수있는 메커니즘이있는 deep_copy_ptr
또는 value_ptr
구현을 찾지 못했습니다. 이는 세밀한 참조 처리 또는 배열 전문화 같은 일이 골대를 벗어났습니다 거친 예리하게 구현이지만, 여기 그럼에도 불구하고 있습니다 :
이
template <typename T>
static void* (*copy_constructor_copier())(void*)
{
return [](void* other)
{ return static_cast<void*>(new T(*static_cast<T*>(other))); };
}
template<typename T>
class smart_copy
{
public:
using copy_function_type = void*(*)(void*);
explicit smart_copy() { static_assert(!std::is_abstract<T>::value, "Cannot default construct smart_copy for an abstract type."); }
explicit smart_copy(copy_function_type copy_function) : copy_function(copy_function) {}
smart_copy(const smart_copy& other) : copy_function(other.get_copy_function()) {}
template<typename U>
smart_copy(const smart_copy<U>& other) : copy_function(other.get_copy_function()) {}
void* operator()(void* other) const { return copy_function(other); }
copy_function_type get_copy_function() const { return copy_function; }
private:
copy_function_type copy_function = copy_constructor_copier<T>();
};
template<typename T,
typename Copier = smart_copy<T>,
typename Deleter = std::default_delete<T>>
class value_ptr
{
using pointer = std::add_pointer_t<T>;
using element_type = std::remove_reference_t<T>;
using reference = std::add_lvalue_reference_t<element_type>;
using const_reference = std::add_const_t<reference>;
using copier_type = Copier;
using deleter_type = Deleter;
public:
explicit constexpr value_ptr() = default;
explicit constexpr value_ptr(std::nullptr_t) : value_ptr() {}
explicit value_ptr(pointer p) : data{p, copier_type(), deleter_type()} {}
~value_ptr()
{
reset(nullptr);
}
explicit value_ptr(const value_ptr& other)
: data{static_cast<pointer>(other.get_copier()(other.get())), other.get_copier(), other.get_deleter()} {}
explicit value_ptr(value_ptr&& other)
: data{other.get(), other.get_copier(), other.get_deleter()} { other.release(); }
template<typename U, typename OtherCopier>
value_ptr(const value_ptr<U, OtherCopier>& other)
: data{static_cast<pointer>(other.get_copier().get_copy_function()(other.get())), other.get_copier(), other.get_deleter()} {}
template<typename U, typename OtherCopier>
value_ptr(value_ptr<U, OtherCopier>&& other)
: data{other.get(), other.get_copier(), other.get_deleter()} { other.release(); }
const value_ptr& operator=(value_ptr other) { swap(data, other.data); return *this; }
template<typename U, typename OtherCopier, typename OtherDeleter>
value_ptr& operator=(value_ptr<U, OtherCopier, OtherDeleter> other) { std::swap(data, other.data); return *this; }
pointer operator->() { return get(); }
const pointer operator->() const { return get(); }
reference operator*() { return *get(); }
const_reference operator*() const { return *get(); }
pointer get() { return std::get<0>(data); }
const pointer get() const { return std::get<0>(data); }
copier_type& get_copier() { return std::get<1>(data); }
const copier_type& get_copier() const { return std::get<1>(data); }
deleter_type& get_deleter() { return std::get<2>(data); }
const deleter_type& get_deleter() const { return std::get<2>(data); }
void reset(pointer new_data)
{
if(get())
{
get_deleter()(get());
}
std::get<0>(data) = new_data;
}
pointer release() noexcept
{
pointer result = get();
std::get<0>(data) = pointer();
return result;
}
private:
std::tuple<pointer, copier_type, deleter_type> data = {nullptr, smart_copy<T>(), std::default_delete<T>()};
};
template<typename T, typename... ArgTypes>
value_ptr<T> make_value(ArgTypes&&... args)
{
return value_ptr<T>(new T(std::forward<ArgTypes>(args)...));;
}
코드는 모든 사람을 위해있는 here를 작동하는 방법을 보여 here 및 테스트를 산다 스스로를 참조하십시오. 의견은 언제나 환영합니다.
이 마음에 드십니까? https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Polymorphic_copy_construction – Hayt
@Hayt : 내 마지막 문장을 읽어보십시오. – rubenvb
'T'와 'U'사이에 새로운 유형을 소개하겠다는 뜻입니다. 따라서 T를 직접 감염시키지 않습니다. – Hayt