如何解决std::shared_ptr<Derived> 如何在没有编译器错误的情况下转换为 std::shared_ptr<Base> ?
// Base class for every object
class Base {
public:
int n_holders {};
};
class Derived : public Base {};
// Custom shared pointer
template<class T>
class Sptr {
public:
T* obj;
Sptr(T* obj_) : obj{obj_} {}
};
void SomeFunc(Sptr<Base> obj) {}
void SomeFunc2(std::shared_ptr<Base> obj) {}
int main()
{
auto a = Sptr<Base>(new Base());
SomeFunc(a); // OK
auto b = Sptr<Derived>(new Derived());
SomeFunc(b); // Error. No matching function call to SomeFunc
auto c = std::shared_ptr<Base>(new Base());
SomeFunc2(c); // OK
auto d = std::shared_ptr<Derived>(new Derived());
SomeFunc2(d); // OK !!!
}
我的问题是,如果使用 Sptr<Derived>
没有错误,为什么编译器不能自动从 Sptr<Base>
强制转换为 std::shared_ptr
?如何使它成为可能?
解决方法
std::shared_ptr
有一个构造函数(来自 cppreference):
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept; (9)
这个重载...
构造一个共享管理对象所有权的 shared_ptr 由河如果 r 不管理任何对象,this 也不管理任何对象。这 如果 Y 是,模板重载不参与重载决议 不能隐式转换为(直到 C++17)兼容(因为 C++17) T*。
因此,从某种意义上说,棘手的部分不是转换共享指针,而是在指针类型不可隐式转换时阻止它。您可以使用 SFINAE 来实现这一点。
以下是一个玩具示例,仅当 Bar<T1>
继承自 Bar<T2>
时才启用从 T1
到 T2
的转换(但不是相反):
#include <type_traits>
template <typename T1>
struct Bar {
Bar() {}
template <typename T2,typename std::enable_if_t<std::is_base_of_v<T1,T2>,int> = 0>
Bar(Bar<T2>){}
};
struct Foo {};
struct Derived : Foo {};
int main(){
Bar<Derived> d;
Bar<Foo> b;
//d = b; // eror
b = d; // OK
}
您可能希望它更通用,就像共享指针一样,只要 T2*
可以转换为 T1*
,而不仅仅是在它们相互继承时(参见 {{3} },我不得不承认,我并不真正理解 C++17 带来的变化,所以我只能猜测:在这种情况下可能是 std::is_convertible
)。因此,要模仿 C++17 之前的智能指针,您可以使用:
template <typename T2,typename std::enable_if_t<std::is_convertible_v<T2*,T1*>,int> = 0>
Bar(Bar<T2>){}
启用所有 T2
的转换,其中 T2*
可以转换为 T1*
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。