Reputation: 75
The code bellow can compile in Visual Studio, but is failed in gcc.
template<typename Isth>
class A
{
public:
A(const boost::shared_ptr<Isth>& obj) {...}
...
};
In class B's method:
A<Isth1> B::method1
{
boost::shared_ptr<Isth2> myPtr = boost::make_shared<Isth2>();
//Isth2 is derived from Isth1;
...
return myPtr;
}
In gcc, I got an error "could not convert 'myPtr' from 'boost::shared_ptr' to 'A'" I think A's constructor should be called when B::method1 return.
Thanks in advance!
Upvotes: 1
Views: 155
Reputation: 481
You're trying to do here multiple implicit conversions:
boost::shared_ptr<Isth2>
-> boost::shared_ptr<Isth1>
-> A<Isth1>
As C++ standard says in the chapter 12.3 Conversions:
- At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
This fixes the compilation:
A<Isth1> B::method1()
{
boost::shared_ptr<Isth2> myPtr = boost::make_shared<Isth2>();
//Isth2 is derived from Isth1;
...
return A<Isth1>(myPtr);
}
Updated:
If you dont want to modify the return value, you could modify the constructor in your A
class:
template <class Isth>
class A
{
...
template <class T> A(const boost::shared_ptr<T>&) { ... }
...
};
Upvotes: 1
Reputation: 507005
The problem was highlighted by others - shared_ptr<Isth2>
can only be converted to the constructor parameter of A<Isth1>
if it wouldn't require a user defined conversion. But since it does, that constructor cannot be used.
Again uniform initialization helps to make this work
A<Isth1> B::method1()
{
boost::shared_ptr<Isth2> myPtr = boost::make_shared<Isth2>();
//Isth2 is derived from Isth1;
...
return { myPtr };
}
For uniform initialization of a return value, user defined conversions for the constructor parameter is allowed. If you want to only change class A
, you probably want to write some SFINAE
template<typename T, typename std::enable_if<
std::is_base_of<Isth, T>::value, bool>::type = true>
A(const boost::shared_ptr<T>& obj) {...}
You are basically stating "I am implicitly converting from any shared ptr that points at an object derived from Isth
".
Upvotes: 5
Reputation: 62583
I am surprised Visual Studio compiles it. How do you expect to return a shared_ptr instead of an actual object? There is no way shared_ptr<X>
can be converted to X.
OK, some clarifications are in order. That sort of conversion would have require to custom-conversion - one from shared_ptr<Isth2>
to shared_ptr<Isth>
, and another from shared_ptr<Isth>
to A. Standard explicitly says that only one custom conversion is allowed. GCC is correct.
As to why Visual Studio is converting it, I am not sure. It either eagerly performs double conversion or it does not treat shared_ptr conversions as a custom conversion. Both options are wrong in my view.
Upvotes: 1