Suppose I have two unrelated classes A
and B
. I also have a class Bla
that uses boost::shared_ptr
like this:
class Bla {
public:
void foo(boost::shared_ptr<const A>);
void foo(boost::shared_ptr<const B>);
}
Notice the const. That's the important part which the original version of this question lacked. This compiles, and the following code works:
Bla bla;
boost::shared_ptr<A> a;
bla.foo(a);
However, if I switch from using boost::shared_ptr
to using std::shared_ptr
in the above examples, I get a compilation error that says:
"error: call of overloaded 'foo(std::shared_ptr<A>)' is ambiguous
note: candidates are: void foo(std::shared_ptr<const A>)
void foo(std::shared_ptr<const B>)
Can you help me figure out why the compiler can't figure out which function to use in the std::shared_ptr case, and can in the boost::shared_ptr case? I'm using the default GCC and Boost versions from the Ubuntu 11.04 package repository which are currently GCC 4.5.2 and Boost 1.42.0.
Here is the full code that you can try compiling:
#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
// #include <memory>
// using std::shared_ptr;
class A {};
class B {};
class Bla {
public:
void foo(shared_ptr<const A>) {}
void foo(shared_ptr<const B>) {}
};
int main() {
Bla bla;
shared_ptr<A> a;
bla.foo(a);
return 0;
}
By the way, this issue motivated me to ask this question about whether I should be using std::shared_ptr
at all yet ;-)
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
).
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));
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