c++ - 为什么shared_ptr不能解析函数接口(interface)中的继承关系?

标签 c++ templates boost c++11

这是一个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

}

有或没有 boost,无论我使用什么编译器,我都会在 #1 上遇到错误,因为 shared_ptr<KBOOM>不要继承 shared_ptr<K<int>> . 然而,KBOOM确实继承自 K<int> .您可以看到 #2 有效,因为 shared_ptr 旨在允许将子类指针隐式传递给基类指针,如原始指针。

所以我的问题是:

  1. 是什么阻止了 std::shared_ptr 实现者使其在情况 #1 中工作(我的意思是,假设标准确实阻止了这种情况,应该是有原因的);
  2. 有没有办法写auto 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
}

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

只有所有模板参数都被明确推导以产生完美匹配(除了标准允许的少数异常(exception)),在重载决策期间才会考虑参数之间可能的转换。

解决方法:

可以根据 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 .

关于c++ - 为什么shared_ptr不能解析函数接口(interface)中的继承关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15815038/

相关文章:

c++ - 有没有一种方法可以在不使用命名空间 std 或以 std::为前缀的情况下引用 cout?

c++ - 多次使用 Promise

c++ - 包含一组自身和自定义比较器的类——循环引用

C++ 创建有序链表

c++ - 使用 boost::future/boost::promise 无法跨线程正确传播异常

c++ - 使用 QMessageBox 为 QPushButtons 释放内存

c++ - C++的数据记录和提取软件

具有类成员的 C++ 模板类

c++ - unix 时间戳到 boost::posix_time::ptime

c++ - cmake链接多个版本的boost/Cmake单独编译源文件