加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 为什么shared_ptr不能解析函数接口中的继承关系?

发布时间:2020-12-16 09:43:53 所属栏目:百科 来源:网络整理
导读:这是一个 simplified example: #include memory#include vectortemplate class T class K {public: virtual ~K(){}};class KBOUM : public Kint{};template class U void do_something( std::shared_ptr KU k ) { }int main(){ auto kboom = std::make_shar
这是一个 simplified example:

#include <memory>
#include <vector>

template< class T >
class K 
{
public:
    virtual ~K(){}
};

class KBOUM : public K<int>{};

template< class U >
void do_something( std::shared_ptr< K<U> > k ) { }

int main()
{
   auto kboom = std::make_shared<KBOUM>();
    do_something( kboom );  // 1 : error

   std::shared_ptr< K<int> > k = kboom; // 2 : ok
   do_something( k ); // 3 : ok

}

无论有没有提升,无论我使用何种编译器,我都会在#1上遇到错误,因为shared_ptr< KBOOM>不要从shared_ptr< K< int>>继承.
但是,KBOOM确实从K< int>继承.您可以看到#2有效,因为shared_ptr旨在允许隐式地将子类指针传递给基类指针,就像原始指针一样.

所以我的问题是:

>什么阻止std :: shared_ptr实现者使它在#1的情况下工作(我的意思是,假设标准确实阻止了这种情况,应该有一个原因);
>有没有办法写自动kboom = std :: make_shared< KBOUM>(); do_something(kboom);不查看KBOOM继承的K的int类型?

注意:我想避免函数的用户必须写

std::shared_ptr<K<int>> k = std::make_shared<KBOOM>();

要么

do_something( std::shared_ptr<K<int>>( kboom ) );

解决方法

这与std :: shared_ptr<>无关.实际上,您可以将其替换为任何类模板并获得相同的结果:

template<typename T> struct X { };

class KBOUM : public X<int> { };

template<typename U>
void do_something(X<K<U>> k) { }

int main()
{
    X<KBOUM> kboom;
    do_something(kboom); // ERROR!

    X<K<int>> k;
    do_something(k); // OK
}

这里的问题是类型参数推导试图找到完美匹配,并且不尝试派生到基础的转换.

只有在明确推断出所有模板参数以产生完美匹配(标准允许的少数例外)之后,才会在重载决策期间考虑参数之间的可能转换.

解决方法:

可以根据KerrekSB在this Q&A on StackOverflow发布的解决方案找出解决方法.首先,我们应该定义一个类型特征,它允许我们判断某个类是否来自某个模板的实例:

#include <type_traits>

template <typename T,template <typename> class Tmpl>
struct is_derived
{
    typedef char yes[1];
    typedef char no[2];

    static no & test(...);

    template <typename U>
    static yes & test(Tmpl<U> const &);

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes);
};

然后,我们可以使用SFINAE重写do_something(),如下所示(注意C 11允许函数模板参数的默认参数):

template<class T,std::enable_if<is_derived<T,K>::value>* = nullptr>
void do_something(X<T> k) 
{ 
    // ...
}

通过这些更改,程序将正确编译:

int main()
{
    X<KBOUM> kboom;
    do_something(kboom); // OK

    X<K<int>> k;
    do_something(k); // OK
}

这是一个live example.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读