OK, having looked at the comments I now realise that what you wanted was a version of dynamic_pointer_cast
for unique_ptr
s.
Remembering that unique_ptrs are well... unique, here is the answer:
Note that this answer may appear at first glance to be un-necessarily complex, but I think it's important to remember that unique_ptr
s can have custom deleters. If we dynamic cast the unique_ptr into new one, the deleter must follow, but without the insertion of a translating shim, the pointer passed to the new unique_ptr's deleter would be of the wrong type.
This code not only dynamically moves ownership to a new pointer type, but also wires in the correct reverse pointer cast so that the object can be deleted on the correct interface by the correct deleter when the moved-to unique_ptr
finally goes out of scope.
#include <iostream>
#include <memory>
template<class Dest, class Source, class Deleter>
auto
make_proxy_deleter(std::unique_ptr<Source, Deleter>& source)
{
return [original = source.get_deleter()](Dest* p) {
original(dynamic_cast<Source*>(p));
};
}
template<class Dest, class T, class Deleter>
auto
dynamic_cast_unique(std::unique_ptr<T, Deleter>&& source)
{
auto proxy_deleter = make_proxy_deleter<Dest>(source);
auto p = dynamic_cast<Dest*>(source.get());
if (!p) {
return std::unique_ptr<Dest, decltype(proxy_deleter)>(nullptr,
std::move(proxy_deleter));
// or... throw std::invalid_argument("not convertible");
}
return std::unique_ptr<Dest, decltype(proxy_deleter)>(dynamic_cast<Dest*>(source.release()),
std::move(proxy_deleter));
}
struct A {
virtual ~A() {};
};
struct B {
virtual ~B() {};
};
struct C: A, B {};
using namespace std;
auto main() -> int
{
auto pa = make_unique<C>();
auto pb = dynamic_cast_unique<B>(std::move(pa));
return 0;
}