c++ - std::shared_ptr、继承和模板参数推导问题

标签 c++ templates inheritance c++11 smart-pointers

我正在尝试将模板参数推导与继承和 std::shared_ptr 一起使用.正如您在下面的示例代码中看到的,我传递了 shared_ptr<Derived>到一个模板化的非成员函数,它应该做模板参数推导。如果我手动命名类型一切正常,如果我让它做模板参数推导它就不行。 似乎 好像编译器无法确定类型,但错误消息显示它确实如此。我不确定这里发生了什么,如果有任何意见,我将不胜感激。 (Visual Studio 2010)

#include <memory>

template <typename T>
class Base {};

class Derived : public Base<int> {};

template <typename T>
void func(std::shared_ptr<Base<T> > ptr) {};

int main(int argc, char* argv[])
{
   std::shared_ptr<Base<int>> myfoo(std::shared_ptr<Derived>(new Derived)); // Compiles
   func(myfoo);    // Compiles
   func<int>(std::shared_ptr<Derived>(new Derived));  // Compiles
   func(std::shared_ptr<Derived>(new Derived));  // Doesn't compile. The error message suggests it did deduce the template argument.

   return 0;
}

错误信息:

5> error C2664: 'func' : cannot convert parameter 1 from 'std::tr1::shared_ptr<_Ty>' to 'std::tr1::shared_ptr<_Ty>'
5>          with
5>          [
5>              _Ty=Derived
5>          ]
5>          and
5>          [
5>              _Ty=Base<int>
5>          ]
5>          Binding to reference
5>          followed by
5>          Call to constructor 'std::tr1::shared_ptr<_Ty>::shared_ptr<Derived>(std::tr1::shared_ptr<Derived> &&,void **)'
5>          with
5>          [
5>              _Ty=Base<int>
5>          ]
5>          c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(1532) : see declaration of 'std::tr1::shared_ptr<_Ty>::shared_ptr'
5>          with
5>          [
5>              _Ty=Base<int>
5>          ]
5>

最佳答案

虽然编译器在进行类型推导时可以执行派生到基的转换,但 std::shared_ptr<Derived> 本身是否源自std::shared_ptr<Base<int>> .

两者之间有一个用户定义的转换,允许shared_ptr在多态性方面表现得像常规指针,但编译器在执行类型推导时不会考虑用户定义的转换。

不考虑用户定义的转换,编译器无法推导出 T这将使 shared_ptr<Base<T>>shared_ptr<Derived> 相同或 shared_ptr<Derived> 的基类(再说一次,shared_ptr<Base<int>> 不是 shared_ptr<Derived> 的基类)。

因此,类型推导失败。

要解决这个问题,你可以让你的函数的参数是一个简单的shared_ptr<T> 添加一个 SFINAE 约束,以确保仅当参数的类型派生自(或是)Base 的实例时才选择重载。类模板:

#include <type_traits>

namespace detail
{
    template<typename T>
    void deducer(Base<T>);

    bool deducer(...);
}

template <typename T, typename std::enable_if<
    std::is_same<
        decltype(detail::deducer(std::declval<T>())),
        void
        >::value>::type* = nullptr>
void func(std::shared_ptr<T> ptr)
{
    // ...
}

这里是 live example .

关于c++ - std::shared_ptr、继承和模板参数推导问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16907331/

相关文章:

c# - 在特定窗口上执行 Ctrl-C 而不聚焦它

c++ - 为什么这个初始化列表不能匹配模板参数?

c++ - 函数模板参数推导是否应该考虑转换运算符?

ruby - 如何在 Rails 中获取子类数组

c++ - 如何将派生类的 std::list 而不是父类的 std::list 传递给函数?

c++ - 将指向成员函数的指针作为指向函数的指针传递

c++ - 10 个字符字符串到 Arduino 上的 int

c++ - 如何使用 Boost::Python 包装 C++ OpenCV 代码?

c++ - 采用 Eigen::Tensor 的函数 - 模板参数推导失败

c++ - 仅阻止继承类的一个函数