Given a shared_ptr
to a non-template class, I regularly pass such a variable to methods expecting shared_ptr<const ...>
, like so (https://godbolt.org/z/47eEPr5d1):
#include <iostream>
#include <memory>
class NotTemplated
{
public:
NotTemplated( const int& t ) : val(t) {}
int val;
};
int Foo(std::shared_ptr<const NotTemplated> p)
{
return p->val;
}
int main()
{
auto pNotTemplated = std::make_shared<NotTemplated>( 6 );
std::cout << Foo( pNotTemplated ) << "n";
return 0;
}
And the compiler is smart enough to convert shared_ptr<NonTemplated>
to shared_ptr<const NonTemplated>
However, consider the case when the class is templated (https://godbolt.org/z/devd3G818):
#include <iostream>
#include <memory>
template <typename T>
class Templated
{
public:
Templated( const T& t ) : val(t) {}
T val;
};
template <typename T>
T Foo(std::shared_ptr<const Templated<T>> p)
{
return p->val;
}
//Not adding this overload fails compilation:
//template <typename T>
//T Foo(std::shared_ptr<Templated<T>> p)
//{
// return p->val;
//}
int main()
{
auto pTemplated = std::make_shared<Templated<int>>( 5 );
std::cout << Foo( pTemplated ) << "n";
return 0;
}
The commented function differs from the existing one only by the const
ness of the type inside the shared_ptr
argument. But without it, compiler fails with the following errors:
<source>(28): error C2672: 'Foo': no matching overloaded function found
<source>(28): error C2784: 'T Foo(std::shared_ptr<const Templated<T>>)': could not deduce template argument for 'std::shared_ptr<const Templated<T>>' from 'std::shared_ptr<Templated<int>>'
So:
- Passing a non-
const
param to a function expecting aconst
is obviously known to be ok. - Passing a
smart-pointer
-to-non-const
to function expectingsmart-pointer
-to-const
is also ok.
Why is it that template resolution fails here??
[If it makes any difference, I’m using C++ 17, on MSVC (latest version of Visual Studio 2019]
Edit: The linked duplicate question doesn’t fully answer my question though. As the first godbolt link clearly shows, shared_ptr<A>
does implicitly get converted to shared_ptr<A const>
. I see this happening only when A
itself is a template, so it is something more complicated/delicate than that…
3