5

Modern C++ Design gives the following example:

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

I couldn't figure how ThreadingModel template would be constructed in a fashion that It could accept SmartPtr as parameter, in my mind some crazy recursion is going to happen. How can this be possible?

Edit:

I've tried Potatoswatter (sorry lol) comment:

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

but it did'nt worked.

here is the error that gcc is giving me:

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’
scooterman
  • 1,336
  • 2
  • 17
  • 36

2 Answers2

5

You are trying to pass SmartPtr as a template type argument to ThreadingModel. SmartPtr however is a template, not a concrete type, and the injected class-name is not available in the inheritance list.

Also note that you can't just use default arguments for template parameters in arbitrary positions (§14.1/11):

If a template-parameter has a default template-argument, all subsequent template-parameters shall have a default template-argument supplied.

Your code with those issues fixed:

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);
        // ...
    }
};

Note that while Modern C++ Design is an excellent book, it can't replace a good basic book on templates like Vandevoorde/Josuttis.

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • Makes sense. I've downloaded the source code from Loki and noticed that ThreadingModel isn't present on the class definition. – scooterman Aug 13 '10 at 13:19
0

The recursion is OK because passing a specialization as a template parameter does not directly cause it to be instantiated.

(ThreadingModel<SmartPtr> in the base list is just shorthand for ThreadingModel< SmartPtr< T, CheckingPolicy, ThreadingModel > > which uses the "current specialization.")

I don't know what ThreadingModel is supposed to do, so I can't implement it, but it should have a declaration of the form

template< class Client > class MyThreading

and it cannot access anything inside Client outside of MyThreading member functions. If you use Client and Client depends on MyThreading, then infinite recursion does happen.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Potato, could you provide how the declaration of ThreadingModel Could be implemented? I've tried many ways here and none worked. – scooterman Aug 12 '10 at 23:04
  • hmmm, tried that. It didn't worked using or not using Client insite class. Note that on the example it builds a guard passing this as parameter so it should work. – scooterman Aug 12 '10 at 23:54