如何编写构造函数实现shared_const_ptr<Derived>到shared_const_ptr<Base>的隐式转换
我创建了一个继承自std::shared_ptr<const T>的模板类shared_const_ptr,允许持有者通过克隆实例并重置shared_ptr来修改指向的对象。(T可以是可克隆类或具备拷贝构造函数的类,因此modify方法有两种不同定义)。
std::shared_ptr<Base>可以由std::shared_ptr<Derived>实例隐式构造或拷贝,但我的shared_const_ptr类无法实现该功能。请问如何实现这一特性?我推测需要编写一个接受shared_const_ptr<D>类型参数的模板构造函数(其中D是模板类型C的派生类),但不知具体写法。由于shared_ptr可以实现该功能,我认为这是可行的。
附上代码:
template <typename T, typename = int> struct HasPolymorphicClonage : std::false_type { }; template <typename T> struct HasPolymorphicClonage <T, decltype(&T::clone, 0)> : std::true_type { }; template<typename C> class shared_const_ptr : public std::shared_ptr<const C> { public : shared_const_ptr(const C * c) : std::shared_ptr<const C>(c) {} shared_const_ptr() =default; // 根据T是否提供clone方法定义modify template<typename T1 = C> typename std::enable_if_t<HasPolymorphicClonage<T1>::value,C&> modify() { C * remplacant = (*this)->clone(); this->std::shared_ptr<const C>::reset(remplacant); return *remplacant; } template<typename T1 = C> typename std::enable_if_t<!HasPolymorphicClonage<T1>::value,C&> modify() { C * remplacant = new C(**this); // 使用拷贝构造函数 this->std::shared_ptr<const C>::reset(remplacant); return *remplacant; } };
解决方案
要实现shared_const_ptr<D>到shared_const_ptr<C>的隐式转换(其中D是C的派生类),只需添加带约束的模板构造函数,利用std::is_base_of确保类型安全,同时复用std::shared_ptr自身的派生类转换逻辑。
修改后的完整代码
#include <memory> #include <type_traits> template <typename T, typename = int> struct HasPolymorphicClonage : std::false_type { }; template <typename T> struct HasPolymorphicClonage <T, decltype(&T::clone, 0)> : std::true_type { }; template<typename C> class shared_const_ptr : public std::shared_ptr<const C> { public : shared_const_ptr(const C * c) : std::shared_ptr<const C>(c) {} shared_const_ptr() = default; // 支持从shared_const_ptr<D>隐式构造(D是C的派生类) template<typename D, typename = std::enable_if_t<std::is_base_of_v<C, D>>> shared_const_ptr(const shared_const_ptr<D>& other) : std::shared_ptr<const C>(static_cast<const std::shared_ptr<const D>&>(other)) { } // 支持从shared_const_ptr<D>隐式赋值(D是C的派生类) template<typename D, typename = std::enable_if_t<std::is_base_of_v<C, D>>> shared_const_ptr& operator=(const shared_const_ptr<D>& other) { std::shared_ptr<const C>::operator=(static_cast<const std::shared_ptr<const D>&>(other)); return *this; } // 根据T是否提供clone方法定义modify template<typename T1 = C> typename std::enable_if_t<HasPolymorphicClonage<T1>::value,C&> modify() { C * remplacant = (*this)->clone(); this->std::shared_ptr<const C>::reset(remplacant); return *remplacant; } template<typename T1 = C> typename std::enable_if_t<!HasPolymorphicClonage<T1>::value,C&> modify() { C * remplacant = new C(**this); // 使用拷贝构造函数 this->std::shared_ptr<const C>::reset(remplacant); return *remplacant; } };
关键说明
- 模板构造函数:通过
template<typename D>定义,并用std::enable_if_t<std::is_base_of_v<C, D>>作为默认模板参数,确保只有当D是C的派生类(或相同类型)时,该构造函数才会被启用。 - 复用基类逻辑:构造函数内部将
shared_const_ptr<D>转换为其基类std::shared_ptr<const D>,再利用std::shared_ptr本身支持的派生到基类的隐式转换,完成std::shared_ptr<const C>的构造。 - 赋值运算符重载:同样添加模板赋值运算符,确保赋值操作也支持派生类到基类的隐式转换。
这样修改后,你就可以像使用std::shared_ptr一样,实现shared_const_ptr<Derived>到shared_const_ptr<Base>的隐式构造和赋值了。
内容的提问来源于stack exchange,提问作者Arnaud
相关产品推荐
相关产品推荐

