2010-08-12 21 views
5

Moderno Diseño C++ da el siguiente ejemplo:Uso argumento de clase de plantilla plantilla como parámetro

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

yo no podía entender cómo se construye ThreadingModel plantilla de una manera que podría aceptar SmartPtr como parámetro, en mi mente alguna recursión loca va a suceder. como puede ser esto posible?

Editar:

He intentado Potatoswatter (lo siento lol) comentario:

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

pero DID'NT trabajaban.

aquí es el error que me está dando 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’ 
+0

Ah, sí. Parámetros de plantilla de plantilla. Una de las cosas más confusas de la historia –

+2

Su nuevo código se ve bien. ¿Qué error obtienes y dónde? Además, un Tomatoswatter suena como si fuera un desastre, y trato de evitarlo. – Potatoswatter

Respuesta

5

Está tratando de pasar SmartPtr como una plantilla tipo argumento a ThreadingModel. SmartPtr sin embargo, es una plantilla, no es un tipo concreto, y el injected class-name no está disponible en la lista de herencia.

También tenga en cuenta que no se puede simplemente utilizar argumentos predeterminados para los parámetros de plantilla en posiciones arbitrarias (§14.1/11):

Si un parámetro de plantilla tiene una plantilla-argumento por defecto, todos los posteriores template-parameters tendrá un argumento de plantilla predeterminado suministrado.

su código con los problemas solucionados:

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

Nótese que si bien Moderno C++ Diseño es un libro excelente, no puede sustituir a un buen libro básico en plantillas como Vandevoorde/Josuttis.

+0

Tiene sentido. He descargado el código fuente de Loki y he notado que ThreadingModel no está presente en la definición de clase. – scooterman

0

La recursividad es bien porque pasa una especialización como un parámetro de plantilla no causa directamente a una instancia.

(ThreadingModel<SmartPtr> en la lista de base es sólo la abreviatura de ThreadingModel< SmartPtr< T, CheckingPolicy, ThreadingModel > > que utiliza la "especialización actual.")

No sé lo que se supone ThreadingModel que hacer, así que no puedo ponerlo en práctica, pero debe tener una declaración de la forma

template< class Client > class MyThreading 

y no se puede acceder a cualquier cosa dentro Client exterior de MyThreading funciones miembro. Si usa Client y Client depende de MyThreading, entonces ocurre una recursión infinita.

+0

Potato, ¿podría proporcionarnos cómo se podría implementar la declaración de ThreadingModel? He intentado de muchas maneras aquí y ninguna funcionó. – scooterman

+0

hmmm, intenté eso. No funcionó al usar o no usar la clase de insite del Cliente.Tenga en cuenta que en el ejemplo construye una guardia que pasa esto como parámetro para que funcione. – scooterman

Cuestiones relacionadas