"shared_ptr"如何实现协方差?



可以从shared_ptr<Deriver>复制或构造shared_ptr<Base>(即shared_ptr<Base> ptr = make_shared<Derived>())。但众所周知,模板类不能相互转换,即使模板参数是可转换的。那么shared_ptr如何检查他们的指针的值是否可转换,如果是,则进行转换呢?

是的,默认情况下,同一类模板的专用化几乎没有关系,并且基本上被视为不相关的类型。 但是您始终可以通过定义转换构造函数 (To::To(const From&)) 和/或转换函数 (From::operator To() const来定义类类型之间的隐式转换。

因此,std::shared_ptr所做的是定义模板转换构造函数:

namespace std {
template <class T>
class shared_ptr {
public:
template <class Y>
shared_ptr(const shared_ptr<Y>&);
template <class Y>
shared_ptr(shared_ptr<Y>&&);
// ...
};
}

尽管所示的声明将允许从任何shared_ptr转换为任何其他,而不仅仅是当模板参数类型兼容时。 但标准也说明了这些构造函数([util.smartptr]/5 和 [util.smartptr.const]/18 和 util.smartptr.const]/21):

出于子句 [util.smartptr] 的目的,当Y*可转换为T*YU[N]并且TcvU[]时,Y*的指针类型被称为与指针类型T*兼容

[...]构造函数不得参与重载解析,除非Y*T*兼容。

尽管可以通过任何方式(包括特定于编译器的功能)完成此限制,但大多数实现将使用 SFINAE 技术(替换失败不是错误)强制实施该限制。 一种可能的实现:

#include <cstddef>
#include <type_traits>
namespace std {
template <class Y, class T>
struct __smartptr_compatible
: is_convertible<Y*, T*> {};
template <class U, class V, size_t N>
struct __smartptr_compatible<U[N], V[]>
: bool_constant<is_same_v<remove_cv_t<U>, remove_cv_t<V>> &&
is_convertible_v<U*, V*>> {};
template <class T>
class shared_ptr {
public:
template <class Y, class = enable_if_t<__smartptr_compatible<Y, T>::value>>
shared_ptr(const shared_ptr<Y>&);
template <class Y, class = enable_if_t<__smartptr_compatible<Y, T>::value>>
shared_ptr(shared_ptr<Y>&&);
// ...
};
}

在这里,帮助程序模板__smartptr_compatible<Y, T>充当"特征":它有一个static constexpr成员value当类型按定义兼容时true,否则false。 然后std::enable_if是一个特征,当它的第一个模板参数true时,它的成员类型叫做type,或者当它的第一个模板参数被false时没有一个名为type的成员,使得类型别名std::enable_if_t无效。

因此,如果任一构造函数的模板类型推导Y类型,使Y*T*不兼容,则将该Y替换为enable_if_t默认模板参数是无效的。 由于这是在替换推导的模板参数时发生的,因此效果只是从重载解决的考虑中删除整个函数模板。 有时,SFINAE 技术用于强制选择不同的重载,或者像这里一样(大多数时候),它只会使用户的代码无法编译。 尽管在编译错误的情况下,在输出中的某处出现一条消息表明模板无效会有所帮助,而不是在内部模板代码中更深层次上出现一些错误。 (此外,像这样的 SFINAE 设置使不同的模板可以使用自己的 SFINAE 技术来测试某个模板专用化、类型依赖表达式等是否有效。

它之所以有效shared_ptr有一个模板化的构造函数

template<typename U> shared_ptr(U * ptr);

如果 U* 不可转换为shared_ptr包含的类型,那么您将在shared_ptr实现中的某个位置收到一个错误。

最新更新