Search code examples
c++c++11shared-ptr

How do I cast between subclasses of shared_ptr?


I'm subclassing std::shared_ptr and am trying to write a cast() method on the subclass so I can hide static_pointer_cast, but I can't get my code to compile. What am I missing?

Demo: http://ideone.com/nbPHbs

template<class T>
class Handle : public std::shared_ptr<T> {
public:
    template<class ResultType>
    inline Handle<ResultType>
    cast() {
        // Cast Handle to shared_ptr
        auto T_sp = static_cast< std::shared_ptr<T> >(*this);
        // Cast the data
        auto ResultType_sp = std::static_pointer_cast<ResultType>(T_sp);
        // Cast back to Handle
        return static_cast< Handle<ResultType> >(ResultType_sp);
    }
};


// Usage
struct Base {};
struct Child : public Base {};
auto child_ptr = Handle<Child>(new Child());
auto base_ptr  = child_ptr.cast<Base>(); // Error with this

This is the Error message I get:

error: no matching function for call to 'Handle<Child>::Handle(Child*)'
auto child_ptr = Handle<Child>(new Child());
                                         ^

**EDIT I'm using inheritance here because it was write-once/throw-away code that was originally template<T> using std::shared_ptr<T> Handle<T>; So, inheritance was the natural progression that required the least amount of code changes. Since it did look like this piece of code will stick around a little longer, I did switch to composition before posting this SO question, I just wanted to know why it wasn't compiling; I haven't done any c++ in a few years, so my skills are a little rusty.


Solution

  • This answer is skipping the discussion as to whether inheriting from std::shared_ptr is a good idea or not. I would though recommend reading such discussion before continuing further.

    Now to your immediate problem:

    If you really want to continue this route then what you are missing is the constructors. The compiler is only creating a default constructor for you. As the error message shows you need Handle<Child>::Handle(Child*).

    The easiest way to get the needed constructors would be to reuse the ones from the base class:

    template<class T>
    class Handle : public std::shared_ptr<T> {
    public:
        using std::shared_ptr<T>::shared_ptr;
    ...