Search code examples
c++templatesshared-ptr

type deduction fail: shared_ptr of derived template to base template as function argument


Here I declared two template classes: A and B, B derives from A:

template<typename T>
class A {
public:
    int a;
    T t;
};

template<typename T>
class B : public A<T> {
public:
    int b;
};

And I make a shared_ptr<B<T>> and assign it to shared_ptr<A<T>>, it's ok:

auto b = std::make_shared<B<std::string>>();
std::shared_ptr<A<std::string>> a = b;

Here I declared a template function accept shared_ptr A<T>:

template<typename T>
void proc(std::shared_ptr<A<T>> &a) {
    std::cout << a->a << std::endl;
}

it accepts a as argument, but rejects b:

proc<std::string>(a); // OK
proc<std::string>(b); // template argument deduction/substitution failed
                      // cannot convert 'b' (type 'std::shared_ptr<B<std::__cxx11::basic_string<char> > >') to type 'std::shared_ptr<A<std::__cxx11::basic_string<char> > >&'

I use g++ as compiler with -std=c++11.

This error brings me a lot problems and how could I fix this elegantly?


Solution

  • Given proc<std::string>(b);, b needs to be converted to std::shared_ptr<A<std::string>>. That means a temporary std::shared_ptr<A<std::string>> will be constructed and then passed to proc. The parameter type of proc is an lvalue-reference to non-const, i.e. std::shared_ptr<A<T>> &, which can't bind to temporaries.

    You can change the parameter type to lvalue-reference to const, which could bind to temporaries. e.g.

    template<typename T>
    void proc(const std::shared_ptr<A<T>> &a) {
    //        ^^^^^
        std::cout << a->a << std::endl;
    }