为什么shared_ptr无法解析函数接口中的继承关系? [英] Why can't shared_ptr resolve inheritance relationships in function interface?

查看:295
本文介绍了为什么shared_ptr无法解析函数接口中的继承关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简化示例:

#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

}

无论是否使用boost,无论我使用什么编译器,我都会在#1上遇到错误,因为shared_ptr<KBOOM>不继承自shared_ptr<K<int>>. 但是,KBOOM确实是从K<int>继承的.您可以看到#2起作用,因为shared_ptr旨在允许将子类指针隐式传递给基类指针,例如原始指针.

With or without boost, whatever the compiler I use I get an error on #1 because shared_ptr<KBOOM> don't inherit from shared_ptr<K<int>> . However, KBOOM does inherit from K<int>. You can see that #2 works because shared_ptr is designed to allow implicitly passing a child class pointer to a base class pointer, like raw pointers.

所以我的问题是:

  1. 阻止std :: shared_ptr实现程序使其在情况#1下工作的原因(我的意思是,假设标准确实阻止了这种情况,应该有原因);
  2. 有没有一种方法可以编写auto kboom = std::make_shared<KBOUM>(); do_something( kboom );而不查看KBOOM继承自K的int类型?
  1. what prevent std::shared_ptr implementer to make it work in case #1 (I mean, assuming that the standard does prevent this case, there should be a reason);
  2. is there a way to write auto kboom = std::make_shared<KBOUM>(); do_something( kboom ); without looking the int type from K from which KBOOM inherit?

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

Note: I want to avoid the user of the function to have to write

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

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

推荐答案

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

This is not related to std::shared_ptr<>. In fact, you could replace that with any class template and get the very same result:

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
}

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

The problem here is that type argument deduction is trying to find a perfect match, and derived-to-base conversions are not attempted.

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

Only after all template parameters have been unambiguously deduce to produce a perfect match (with the few exceptions allowed by the Standard), possible conversions between arguments are considered during overload resolution.

解决方法:

可以根据 KerrekSB 发布的解决方案找出解决方法. https://stackoverflow.com/a/12182195/1932150">StackOverflow上的此问题与解答.首先,我们应该定义一个类型特征,以使我们能够确定某个类是否从某个模板的实例派生而来:

It is possible to figure out a workaround based on a solution posted by KerrekSB in this Q&A on StackOverflow. First of all, we should define a type trait that allow us to tell whether a certain class is derived from an instance of a certain template:

#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允许使用函数模板参数的默认参数):

Then, we could use SFINAE to rewrite do_something() as follows (notice that C++11 allows default arguments for function template parameters):

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

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

With these changes, the program will correctly compile:

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

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

这是一个在线示例.

这篇关于为什么shared_ptr无法解析函数接口中的继承关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆