为什么 shared_ptr 不是 Derived 隐式转换为 shared_ptr 到 Base
Why isn't shared_ptr to Derived implicitly converted to shared_ptr to Base
我不明白为什么在下面的代码中,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>>());
}
我遇到了,这似乎与我有关。我是不是因为制作了函数的模板而出错?
我得到的错误是:
E0304 no instance of function template "foo" matches the argument list
C2664 'std::shared_ptr<Base<int>> foo<int>(std::shared_ptr<Base<int>>)': cannot convert argument 1 from 'std::shared_ptr<Derived<int>>' to 'std::shared_ptr<Base<int>>'
此行为的原因是 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
成员添加到基础 class。这不是绝对必要的,但可以简化代码。
我不明白为什么在下面的代码中,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>>());
}
我遇到了
我得到的错误是:
E0304 no instance of function template "foo" matches the argument list
C2664 'std::shared_ptr<Base<int>> foo<int>(std::shared_ptr<Base<int>>)': cannot convert argument 1 from 'std::shared_ptr<Derived<int>>' to 'std::shared_ptr<Base<int>>'
此行为的原因是 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
成员添加到基础 class。这不是绝对必要的,但可以简化代码。