2013-07-25 3 views
16

У меня есть менеджер ресурсов, который, как предложил Андрей Александреску в книге Modern C++ Design, следует за политическим дизайном. У меня проблемы, потому что мой менеджер ресурсов должен иметь возможность предоставлять ссылки на себя на управляемые ресурсы на shared_from_this().Использование shared_from_this в шаблонных классах

Я построил минимальный пример, воспроизводящий мою проблему, в результате которой вы можете увидеть here.

В принципе у меня есть некоторые управляемый ресурс, который нуждается в ссылку на его менеджер:

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_; 
}; 

И менеджер, который хранит и предоставляет ресурсы:

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; 
     } 
}; 

Как вы можете видеть, хранить себя в на основе политик. В то время как менеджер создает ресурсы, политика может свободно выбирать между различными подходами к хранению информации (она может, например, выбирать, чтобы ничего не хранить и создавать новые ресурсы каждый раз).

Это пример политики хранения:

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_; 
}; 

Но я получаю ошибку компиляции:

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>’ 

Для выхода полной компиляции см minimal example.

Невозможно использовать std::enable_shared_from_this и shared_from_this() в рамках основанного на политике дизайна? Если нет, каков его правильный способ?

+0

manager_ptr const & parent? –

ответ

33

enable_shared_from_this<manager<Policy>> является «зависимой базой» (это базовый класс, тип которого зависит от параметра шаблона, в данном случае Policy), поэтому правила C++ говорят, что поиск неквалифицированного имени не выглядит там, вам нужно сказать this->shared_from_this() или std::enable_shared_from_this<manage<Policy>>::shared_from_this(), чтобы найти элемент из зависимой базы.

См. http://gcc.gnu.org/wiki/VerboseDiagnostics#dependent_base для получения более подробной информации и ссылки на другие ссылки.

Чтобы исправить вторую ошибку, вам необходимо сделать enable_shared_from_this базовый класс общественного, или он не может получить инициализируется, когда менеджер принадлежит shared_ptr.

+0

Данная ссылка была хорошая –

4

Компилятор сообщает вам, что проблема связана с зависимым именем и поиском независимого имени. «Зависимый» означает «зависит от параметра шаблона».

Независимые имена проверяются при анализе шаблона (сначала), а зависимые имена (и их члены) проверяются только при создании экземпляра шаблона.

В вашем случае имя shared_from_this не зависит от параметров шаблона, поэтому компилятор хочет получить к нему доступ при разборе шаблона. Тем не менее, ваш класс получает его от enable_shared_from_this<manager<Policy>>, который делает в зависимости от параметра шаблона, и поэтому учитывается только время создания экземпляра.

Вы должны изменить shared_from_this на зависимое имя.У вас есть два варианта:

  1. Квалифицируйте его чем-то зависимым. Самый простой - использовать this->shared_from_this().

  2. Привести его в рамки явно, поставив используя декларацию в ваше определение класса: using std::enable_shared_from_this<manager<Policy>>::shared_from_this;

-1

Как уже написано, вы должны использовать this->shared_from_this(). Но это не realy help. Я отредактировал ваш код дальше и сделал все общедоступным (все classes как structs и не, private, ...). Теперь это compiles. Иногда лучше не думать о ограничении доступа к членам при выполнении прототипирования (поскольку это может привести к большим ошибкам компиляции). Это можно сделать позже, когда тесты будут в порядке.

+0

Только базовый класс 'enable_shared_from_this' должен быть общедоступным. –

+0

@JonathanWakely может быть, но это не моя задача разработать этот код. Я только показал больше проблем. До тех пор, пока компонент не находится в производственном коде, и интерфейсы могут измениться, может быть проще сделать все общедоступным (как я написал). Конечно, в конце нужно подумать о ограничительном доступе участников. Но при разработке он может создавать больше ошибок, как в этом примере. –

+3

Я по-прежнему считаю, что нарушение инкапсуляции - это не путь, даже если не в производстве. Я предпочел бы заранее знать потенциальные проблемы с инкапсуляцией, прежде чем публиковать интерфейс, а затем заметить, что я изо всех сил стараюсь изо всех сил. – nijansen

Смежные вопросы