Использовать шаблонный аргумент класса шаблона в качестве параметра - PullRequest
5 голосов
/ 13 августа 2010

Современный C ++ Design приводит следующий пример:

template <class T> struct EnsureNotNull
{
    static void Check(T*& ptr)
    {
      if (!ptr) ptr = GetDefaultValue();
    }
};

template
<
   class T,
   template <class> class CheckingPolicy = EnsureNotNull,
   template <class> class ThreadingModel
>
class SmartPtr
  : public CheckingPolicy<T>
  , public ThreadingModel<SmartPtr>
{
...
  T* operator->()
  {
    typename ThreadingModel<SmartPtr>::Lock guard(*this);
    CheckingPolicy<T>::Check(pointee_);
    return pointee_;
  }
private:
  T* pointee_;
};

Я не мог понять, как шаблон ThreadingModel будет построен таким образом, чтобы он мог принимать SmartPtr в качестве параметра, на мой взгляд, произойдет какая-то безумная рекурсия. Как это возможно?

Edit:

Я пробовал Potatoswatter (извините, лол) комментарий:

template <class SmartPtr> struct SingleThreadingModel
{
  class Lock
  {
    public: 
      Lock(SmartPtr&)
      {
      }
  };
};

но это не сработало.

вот ошибка, которую дает мне gcc:

main.cpp:28:35: error: type/value mismatch at argument 1 in template parameter list for ‘template<class> class ThreadingModel’
main.cpp:28:35: error:   expected a type, got ‘SmartPtr’

Ответы [ 2 ]

5 голосов
/ 13 августа 2010

Вы пытаетесь передать SmartPtr в качестве шаблона введите аргумент ThreadingModel.SmartPtr, однако, является шаблоном, а не конкретным типом, и внедренное имя класса недоступно в списке наследования.

Также обратите внимание, что нельзя просто использовать аргументы по умолчанию для параметров шаблона в произвольных позициях ( §14.1 / 11 ):

Если параметр шаблонаимеет аргумент шаблона по умолчанию, все последующие параметры шаблона должны иметь аргумент шаблона по умолчанию.

Ваш код с этими проблемами исправлен:

template
<
  class T,
  template <class> class ThreadingModel,
  template <class> class CheckingPolicy = EnsureNotNull
>
class SmartPtr
  : public CheckingPolicy<T>
  , public ThreadingModel<SmartPtr<T, ThreadingModel, CheckingPolicy> > 
//                         ^ .... now passing a concrete class .... ^
{
    T* operator->() {
        // the following use of SmartPtr is fine as it is the injected class-name:
        typename ThreadingModel<SmartPtr>::Lock guard(*this);
        // ...
    }
};

Обратите внимание, что пока Modern C ++ Design - отличная книга, она не может заменить хорошую базовую книгу о таких шаблонах, как Vandevoorde / Josuttis .

0 голосов
/ 13 августа 2010

Рекурсия в порядке, потому что передача специализации в качестве параметра шаблона напрямую не вызывает его создание.

(ThreadingModel<SmartPtr> в базовом списке является просто сокращением для ThreadingModel< SmartPtr< T, CheckingPolicy, ThreadingModel > >, который использует «текущую специализацию».)

Я не знаю, что должен делать ThreadingModel, поэтому я не могу его реализовать, но он должен иметь объявление вида

template< class Client > class MyThreading

и он не может получить доступ к чему-либо внутри Client вне MyThreading функций-членов. Если вы используете Client и Client зависит от MyThreading, то бесконечная рекурсия действительно происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...