tags:

views:

100

answers:

2

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

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
Potato, could you provide how the declaration of ThreadingModel Could be implemented? I've tried many ways here and none worked.
scooterman
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
+2  A: 

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
Makes sense. I've downloaded the source code from Loki and noticed that ThreadingModel isn't present on the class definition.
scooterman