提问者:小点点

为什么shared_ptr到派生不隐式转换为shared_ptr到基


我不明白为什么在下面的代码中,shared_ptr

#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

我得到的错误是:

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

C2664'标准::shared_ptr


共1个答案

匿名用户

这种行为的原因是,<code>foo</code>是一个模板。请注意,如果<code>foo</code>不是模板,则一切都正常工作:

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

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

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

#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成员。这不是严格必要的,但简化了代码。