问题描述
我不明白为什么在下面的代码中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 >'
解决方法
此行为的原因是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
成员。这不是严格必要的,但是可以简化代码。