Suppose I have two unrelated classes A
and B
. I also have a class Bla
that uses boost::shared_ptr
like t
The following compiles fine with GCC 4.5 and Visual Studio 10. If you say it doesn't compile in GCC 4.5.2 then it sounds like a compiler bug which you should report (but make sure that it really happens it's more likely that you made some sort of typo).
#include <memory>
class A{};
class B{};
class Bla {
public:
void foo(std::shared_ptr<A>) {}
void foo(std::shared_ptr<B>) {}
};
int main()
{
Bla bla;
std::shared_ptr<A> a;
bla.foo(a);
}
You can use std::static_pointer_cast
to add the const
qualification:
bla.foo(std::static_pointer_cast<const A>(a));
http://bytes.com/topic/c/answers/832994-shared_ptr-derived-classes-ambiguitity-overloaded-functions
struct yes_type { char dummy; };
struct no_type { yes_type a; yes_type b; };
template < typename From, typename To >
class is_convertible
{
private:
static From* dummy ( void );
static yes_type check ( To );
static no_type check ( ... );
public:
static bool const value = sizeof( check( *dummy() ) ) == sizeof( yes_type );
}; // is_convertible
An in boost's shared_ptr.h, change the constructor signature to:
template<class Y>
shared_ptr(shared_ptr<Y> const & r,
typename enable_if<is_convertible<Y*, T*>::value, void*>::type = 0
): px(r.px), pn(r.pn) // never throws
{
}
shared_ptr
has a template single-argument constructor, which is considered for the conversion here. That's what allows an actual parameter shared_ptr<Derived>
to be supplied where a shared_ptr<Base>
is needed.
Since both shared_ptr<const A>
and shared_ptr<const B>
have this implicit conversion, it's ambiguous.
At least in C++0x, the standard requires that shared_ptr
use some SFINAE tricks to make sure that the template constructor only matches types that actually can be converted.
The signature is (see section [util.smartptr.shared.const]
):
shared_ptr<T>::shared_ptr(const shared_ptr<T>& r) noexcept;
template<class Y> shared_ptr<T>::shared_ptr(const shared_ptr<Y>& r) noexcept;
Requires: The second constructor shall not participate in the overload resolution unless
Y*
is implicitly convertible toT*
.
Possibly the library hasn't yet been updated to comply with that requirement. You might try a newer version of libc++.
Boost won't work, because it's missing that requirement.
Here's a simpler test case: http://ideone.com/v4boA (This test case will fail on a conforming compiler, if it compiles successfully, it means the original case will be incorrectly reported as ambiguous.)
VC++ 2010 gets it right (for std::shared_ptr
).