【问题标题】:Why isn't shared_ptr to Derived implicitly converted to shared_ptr to Base为什么不将 shared_ptr to Derived 隐式转换为 shared_ptr to Base
【发布时间】:2021-02-04 16:08:30
【问题描述】:

我不明白为什么在下面的代码中,shared_ptr<Derived<int>> 没有隐式转换为 shared_ptr<Base<int>>

#include <memory>
    
template <typename T>
class Base {
};
    
template <typename T>
class Derived : public Base<T> {
};
    
template <typename T>
T foo(std::shared_ptr<Base<T>>) {
    return T{};
}
    
void main() {
    foo(std::make_shared<Base<int>>());
    foo(std::make_shared<Derived<int>>());
}

我遇到了convert std::shared_ptr<Derived> to const shared_ptr<Base>&,这似乎与我有关。我是否因为制作了函数模板而出错?

我得到的错误是:

E0304 没有函数模板“foo”的实例与参数列表匹配

C2664 'std::shared_ptr> foo(std::shared_ptr>)':无法从 'std::shared_ptr>' 转换参数 1到 'std::shared_ptr>'

【问题讨论】:

  • 您能否创建一个minimal reproducible example 并将其包含在您的问题中?编译它并包含它产生的确切错误消息。
  • @Eljay 虽然它是隐式可转换的。
  • @UlrichEckhardt 我不确定你还想要什么,我发布了整个代码以及我从编译器收到的唯一错误消息
  • @user 由于其他原因,此代码不可编译。这不是最小的可重现示例。
  • @user 在引用包含&lt;...&gt; 对的内容时,您需要使用&amp;lt;,因此它们不会与HTML 标记混淆。我已经为您编辑了错误消息,因此&lt; 可以正确显示。

标签: c++ templates inheritance shared-ptr


【解决方案1】:

这种行为的原因是foo 是一个模板。请注意,如果foo 不是模板,则一切正常:

int foo(std::shared_ptr<Base<int>>) {
    return int{};
}

但是,当foo 是模板时,编译器首先需要实例化foo,并且它希望能够实例化完全匹配,因为此时不应用隐式转换。而且这个实例化不能成功,所以报错。

解决此问题的一种方法是使foo 成为一个非常贪婪的模板,然后添加额外的可转换性约束。例如:

#include <memory>

template <typename T>
class Base {
public:
    using Type = T;
};

template <typename T>
class Derived : public Base<T> {
};

template <typename T>
auto foo(T) -> std::enable_if_t<std::is_convertible_v<T, std::shared_ptr<Base<typename T::element_type::Type>>>, typename T::element_type>
{    
    return typename T::element_type{};
}


int main() {
    foo(std::make_shared<Derived<int>>()); //OK
    foo(20); // error
}

注意,我在基类中添加了一个Type 成员。这不是绝对必要的,但可以简化代码。

【讨论】:

  • 您可以做的一件事是调用foo&lt;int&gt;(std::make_shared&lt;Derived&lt;Int&gt;&gt;());,以允许进行隐式转换,这将使隐式转换变得有用。
  • 好的,但是模板已经在main 的第一次调用中被实例化了,但是你说调用foo(std::make_shared&lt;Derived&lt;int&gt;&gt;()) 不会编译,因为它宁愿找到一个完全匹配而不是实例化从foo(std::make_shared&lt;Base&lt;int&gt;&gt;()); 创建?
  • @user 模板为每次调用模板独立实例化。如果已经实例化了很多,它将被使用(即不会产生新的定义)。之前为某些代码实例化了模板的事实并不意味着它会被盲目使用 - 下一次尝试的过程将相同。
  • @Sergey 好的,有道理,感觉很愚蠢,但这实际上是我想不通的,谢谢
猜你喜欢
  • 2017-08-06
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2012-11-04
  • 1970-01-01
  • 2021-11-28
相关资源
最近更新 更多