Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using shared_from_this in templated classes

I have a resource manager that, like Andrei Alexandrescu proposed in the book Modern C++ Design, follows a policy based design. I am having trouble though, because my resource manager needs to be able to provide references to itself to the managed resources by shared_from_this().

I built a minimal example reproducing my problem, which results you can see here.

Basically I have some managed resource that needs a reference to its manager:

template <typename T> class managed_resource {         typedef std::shared_ptr<manager<T>> manager_ptr;     public:         managed_resource(manager_ptr const & parent)             : parent_(parent)         {         }          /* ... */      private:         manager_ptr parent_; }; 

And a manager that stores and provides resources:

template <typename Policy> class manager     : Policy     , std::enable_shared_from_this<manager<Policy>> {         typedef managed_resource<Policy> resource;         typedef std::shared_ptr<resource> resource_ptr;     public:         resource_ptr get_resource(std::string const & name)         {             Policy & p = *this;             if(p.find(name))             {                 return p.get(name);             }             resource_ptr res = std::make_shared<resource>(shared_from_this());             p.store(name, res);             return res;         } }; 

As you can see, the storing itself is policy-based. While the manager does create the resources, the policy can freely decide between various approaches of storing the information (it could e.g. choose to not store anything and create new resources every time).

This is an example of a storage policy:

class map_policy {         typedef std::shared_ptr<managed_resource<map_policy>> resource_ptr;         typedef std::map<std::string, resource_ptr> resources;      public:         bool find(std::string const & name)         {             resources::iterator res_it = resources_.find(name);             return res_it != resources_.end();         }          resource_ptr get(std::string const & name)         {             resources::iterator res_it = resources_.find(name);             return res_it->second;         }          void store(std::string const & name, resource_ptr const & res)         {             resources_[name] = res;         }      private:         resources resources_; }; 

But I get a compilation error:

error: there are no arguments to ‘shared_from_this’ that depend         on a template parameter, so a declaration of         ‘shared_from_this’ must be available error: ‘std::enable_shared_from_this<manager<map_policy> >’ is         an inaccessible base of ‘manager<map_policy>’ 

For full compilation output see the minimal example.

Is it impossible to use std::enable_shared_from_this and shared_from_this() within policy based design? If not, what is the proper way of using it?

like image 782
nijansen Avatar asked Jul 25 '13 08:07

nijansen


1 Answers

enable_shared_from_this<manager<Policy>> is a "dependent base" (it's a base class whose type depends on a template parameter, in this case Policy) so the rules of C++ say that unqualified name lookup doesn't look in there, you need to say this->shared_from_this() or std::enable_shared_from_this<manage<Policy>>::shared_from_this() to find the member from the dependent base.

See http://gcc.gnu.org/wiki/VerboseDiagnostics#dependent_base for more detail and links to other references.

To fix the second error you need to make enable_shared_from_this a public base class, or it can't get initialized when the manager is owned by a shared_ptr.

like image 59
Jonathan Wakely Avatar answered Sep 19 '22 15:09

Jonathan Wakely