I'm trying to implement my custom version of shared_ptr and weak_ptr. While implementing them, I've got into some problems with it.
In order to accept subclass types from constructor, I had to use another template type U as parameter other than template type of the class 'T'.
Let's say constructor with parameter type U as version 1 and constructor with parameter type T as version 2
Here's my question
WeakPtr<T> weakPtr_a;
WeakPtr<T> weakPtr_b = weakPtr_a; //Shouldn't this be still enough with version 1?
Here are my code snippets
WeakPtr-Decl.hpp
template <typename T>
class WeakPtr
{
T* m_objectPtr = nullptr;
SharedObjectInfo* m_sharedObjectInfoPtr = nullptr;
template <typename U>
friend class WeakPtr;
public:
constexpr WeakPtr();
~WeakPtr() = default;
//! Copy constructor
//! \tparam U : template type of weakPtr to copy from
//! U must be same type as T or subclass of T or assertion will fail
//! \param weakPtr : weakPtr to copy from
template <typename U>
WeakPtr(const WeakPtr<U>& weakPtr); // Version 1
//! Copy constructor
//! \param weakPtr : weakPtr to copy from
WeakPtr(const WeakPtr<T>& weakPtr); // Version 2
};
WeakPtr-Impl.hpp
template <typename T>
template <typename U>
WeakPtr<T>::WeakPtr(const WeakPtr<U>& weakPtr)
: m_objectPtr(weakPtr.m_objectPtr),
m_sharedObjectInfoPtr(weakPtr.m_sharedObjectInfoPtr)
{
static_assert(std::is_same<std::decay_t<T>, std::decay_t<U>>::value ||
std::is_base_of<std::decay_t<T>, std::decay_t<U>>::value);
}
template <typename T>
WeakPtr<T>::WeakPtr(const WeakPtr<T>& weakPtr)
: m_objectPtr(weakPtr.m_objectPtr),
m_sharedObjectInfoPtr(weakPtr.m_sharedObjectInfoPtr)
{
}
As explained in comments, when available an exact non-template constructor (version 2, in your case), it's preferred over a template one (version 1).
I suggest to use delegating constructor, so let the compiler choose the version 2 (when the type is the same) and, from version 2, call version 1.
I propose to add an unused defaulted second parameter in version 1
template <typename U> // ............VVVVVVV
WeakPtr (WeakPtr<U> const & weakPtr, int = 0)
: m_objectPtr{weakPtr.m_objectPtr},
m_sharedObjectInfoPtr{weakPtr.m_sharedObjectInfoPtr}
{ }
and transform version 2 as follows
WeakPtr (WeakPtr const & weakPtr) : WeakPtr{weakPtr, 0}
{ }
The second unused parameter in version 1 is added to permit to select version 1 calling it from version 2.
Observe the zero in WeakPtr{weakPtr, 0}
in delegating call in version 2: the added zero force the call of version 1 because version 2 has only one argument.
The default value is important to permit the direct use of version 1 when the types are different.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.