Reputation: 35982
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace std;
struct TestClass
{
static void Create(boost::shared_ptr<const int> shp)
{
cout << "TestClass::Create: " << *shp << endl;
}
template <typename T>
static void CreateT(boost::shared_ptr<const T> shp)
{
cout << "TestClass::CreateT: " << *shp << endl;
}
};
int main()
{
boost::shared_ptr<int> shpInt = boost::make_shared<int>(10);
boost::shared_ptr<const int> shpConstInt = shpInt;
TestClass::Create( shpInt ); // OK
TestClass::Create( shpConstInt ); // OK
//error C2664: 'void TestClass::CreateT<int>(boost::shared_ptr<T>)' :
//cannot convert parameter 1 from 'boost::shared_ptr<T>' to 'boost::shared_ptr<T>'
TestClass::CreateT( shpInt ); // ERROR
TestClass::CreateT( shpConstInt ); // OK
// workaround
boost::shared_ptr<const int> shpConstInt2 = shpInt;
TestClass::CreateT( shpConstInt2 ); // OK
return 0;
}
Question> Why TestClass::CreateT( shpInt )
doesn't work while TestClass::Create( shpInt )
works fine. Is it because the TestClass::CreateT
is a template function that ONLY supports static binding and it cannot make the automatic conversion from boost::shared_ptr<T>
to boost::shared_ptr<const T>
?
Thank you
Upvotes: 1
Views: 69
Reputation: 75697
The non-templated versions work because there is no type deduction involved. The compiler knows the type from and the type to he has to convert (in case they are not the same types) and simply checks if there is a conversion possible.
For the templated version this is not true anymore. He first has to deduce the template.
For boost::shared_ptr<const int>
to boost::shared_ptr<const T>
this is simple because a perfect match is found: T
is int
(so no conversion is needed nor involved).
For the match from boost::shared_ptr<int>
to boost::shared_ptr<const T>
there is no T
that would yield the same two types. So the question is ‘What is T
?’
To you it might be obvious (and you would be still wrong), but the compiler can't deduce T
because it is not a perfect match. The next best thing would be a conversion between the two types, but that would mean to try all the possibilities of T
(which are infinite) and see which one yields a convertible type. E.g. T
= long
-> boost::shared_ptr<const long>
could be convertible to boost::shared_ptr<int>
or T
= Foo
(where Foo
is a user defined class) -> boost::shared_ptr<const Foo>
could be convertible to boost::shared_ptr<int>
. So there is no way for him to deduce T
. I know that this is not an academic answer, and someone more knowledgeable of the standard could quote the type deduction rules from the standard but ultimately those rules are somewhat motivated by the explanation above.
Upvotes: 2