2

In the following code, why is the call to bar(std::shared_ptr<B>) ambiguous, but bar(std::shared_ptr<A>) is not?

The intent of foo is to treat const and non-const pointers differently. Can I disambiguate this in any other way than changing the call site to bar(std::dynamic_pointer_cast<A>(b))?

#include <memory>

struct A {};
struct B : A {};


void foo(std::shared_ptr<const A>) { }
void foo(std::shared_ptr<A>) { }

void bar(const A &) { }
void bar(A &) { }

int main() {
    A a;
    bar(a); // ok

    B b;
    bar(b); // ok

    auto ap = std::make_shared<A>();
    foo(ap); // ok

    auto bp = std::make_shared<B>();
    foo(bp); // ambiguous

    return 0;
}
jornb87
  • 1,441
  • 10
  • 15

1 Answers1

1

The call is ambiguous as a std::shared_ptr<B> is not a const or non const shared pointer of type A.

As this, it would use an implicit cast operation from std::shared_ptr<B> to std::shared_ptr<A> or std::shared_ptr<const A>. These both options are ambiguous as you always can cast from non const to const.

If you have:

auto bp = std::make_shared<const B>();
foo(bp);

it is not longer ambiguous as a const B can only be casted to const A in this case.

As the implicit cast is ambiguous, you have to use an explicit one in your given scenario.

As a hack you can write some helper template which automatically detects if the given pointer is const or not and pass it with an explicit cast automatically.

template < typename T>  
void foo( std::shared_ptr<T>& ptr)
{
    foo( std::static_pointer_cast<A>(ptr) );
}

template < typename T>  
void foo( std::shared_ptr<const T>& ptr)
{
    foo( std::static_pointer_cast<const A>(ptr) );
}

Now you can use it like:

    auto bp = std::make_shared<B>();
    foo(bp); 
    auto bp2 = std::make_shared<const B>();
    foo(bp2); 
Klaus
  • 24,205
  • 7
  • 58
  • 113