I do not understand why in the following code, the shared_ptr<Derived<int>> isn't implicitly converted to a 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>>());
}
I came across convert std::shared_ptr<Derived> to const shared_ptr<Base>&, which seems related to me. Am I getting an error because I made a template of the function?
The error I get is:
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>>'
The reason for this behavior is the fact that foo is a template. Note, that everything works correctly if foo is not a template:
int foo(std::shared_ptr<Base<int>>) {
return int{};
}
However, when foo is a template, the compiler first needs to instantiate foo, and it wants to be able to instantiate an exact match, since implicit conversions do not apply at this point. And this instantiation can not succeed, thus the error.
One way to workaround this issue would be to make foo a very greedy template, and then add additional constraints of convertibility. For example:
#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
}
Note, that I have added a Type member to the base class. This is not strictly necessary, but simplifies the code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With