Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Problema con template en namespace

Iniciado por Warchief, 16 de Febrero de 2007, 09:52:25 AM

« anterior - próximo »

Warchief

Hola, llevo un rato (largo) dándole vueltas y no consigo hacerlo funcionar. La situación es la siguiente:


// Template para Singleton
template <class ClaseSingleton>
class ISingleton
{
   public:
       static ClaseSingleton& Instance() {
           static ClaseSingleton instancia;
           return instancia;
       }
};

// Template que usa el Singleton como clase base
// BAJO NAMESPACE ElDeLaClase
namespace ElDeLaClase {

   template <class B>
   class A : public ISingleton< A >
   {
       friend class ISingleton<A>;
       private:
           A() { }
           
           B* b;
       public:
           void DoA() {
              b = 0;
           }

   };
};

// El main
int main(int argc, char* argv[])
{
   ElDeLaClase::A<float>::Instance().DoA();

   return 0;
}

Ese código compila perfectamente. Estoy intentando hacerlo funcionar con el Singleton en un namespace.


namespace ElDelSingleton {
   template <class ClaseSingleton>
   class ISingleton
   {
       public:
           static ClaseSingleton& Instance() {
               static ClaseSingleton instancia;
               return instancia;
           }
   };
};


Por lo que modifico el friend a:

   template <class B>
   class A : public ElDelSingleton::ISingleton< A >
   {
            friend class ElDelSingleton::ISingleton<A>;
       // ... etc
   };


Y deja de compilar. Si importo el namespace sí (using), pero me gustaría evitarlo.

También puedo usar la clase sin template
friend class ElDelSingleton::ISingleton;
pero entonces un ISingleton<A> tendría acceso a los miembros privados de ISingleton<B> (pudiendo ser A != B), lo que aunque no es problemático, tampoco me gusta.

La cuestión es, ¿qué tengo que añadir para que el compilador sepa que ISingleton es una template de el namespace ElDelSingleton?

Estoy usando el VS2003. Gracias :)

<Edit>
Por cierto, añado que no hay problema con el friend class ElDelSingleton::ISingleton<A>; cuando A no hereda de ISingleton.

namespace ElDeLaClase {

   template <class B>
   class A
   {
       friend class ElDelSingleton::ISingleton<A>;
   };
};


Eso funciona, pero no puedo llamar a A<int>::Instance(), sino a ISingleton< A<int> >::Instance(), que tampoco es problemático.


Así que tengo tres soluciones, pero ya es curiosidad/empecinamiento en saber por qué no lo hace debido a la herencia.

Warchief

Como el hilo anterior es gigante pongo aquí un resumen final:
Soluciones:

  • Importar el namespace del Singleton
  • Evitar la herencia (llamada a ISingleton< A<B> >)
  • Acceso a los miembros privados sin template [friend class N::ISingleton;]
Código para que el que quiera jugar un rato:
Contiene comentarios especiales y todas las pruebas

namespace ElDelSingleton { // NOTA 1 ) Namespace de la discordia

   template <class ClaseSingleton>
   class ISingleton
   {
       public:
   
           static ClaseSingleton& Instance() {
               static ClaseSingleton instancia;
               return instancia;
           }

           // NOTA 2) Porque A<X> no debería compilar este método si X != int
           static CrearUnInt();
   };
};

// using namespace ElDelSingleton; // NOTA 3.1) Esto hace que funcione tranquilamente, pero no mola!

namespace ElDeLaClase {

   template <class B>
   class A : public ElDelSingleton::ISingleton<A> // Se puede quitar la herencia
   {
       friend class ElDelSingleton::ISingleton<A>; // NOTA 4) Esto es lo que debería funcionar
       // friend class ISingleton<A>; // NOTA 3.2) Esto funciona si se hace using namespace ElDelSingleton
       // friend class ISingleton; // NOTA 6) Esto hace que ISingleton< Z > tenga acceso a privados de A<X>, por lo que CrearUnInt compila para ISingleton< A<B> > con B distinto de int

       // Esto era por rellenar
       A( ) : A( 0 ) { }
       A( B valor ) : b( valor ) { }
       B b;

       // NOTA 5) Si no hay herencia, esto tiene el mismo efecto, pero para qué usar ISingleton entonces?
   //public:
   //    static A<B>& Instance() {
   //        return ElDelSingleton::ISingleton< A<B> >::Instance();
   //    }
   };
};

// Este método no debería compilar salvo para ISingleton< A<int> >
template <class CSing>
ElDelSingleton::ISingleton<CSing>::CrearUnInt()
{
   ElDeLaClase::A<int> unA(5);
}

int main(int argc, char* argv[])
{
   // No debería compilar nunca
   ElDelSingleton::ISingleton< ElDeLaClase::A<float> >::CrearUnInt();
   // Esta es la llamada que molaría
   ElDeLaClase::A<float>::CrearUnInt();
   // Debería compilar sin problemas
   ElDelSingleton::ISingleton< ElDeLaClase::A<int> >::CrearUnInt();


return 0;
}


Warchief

Código más sencillo y que no compila por friend class NB::B< A >;
namespace NB {
   template< class TB >
   class B {
   public:
       static void CrearA() {
           TB laTemplate;
       }
   };
}

namespace NA {
   template <class TA>
   class A : public NB::B<A> {
       friend class NB::B< A >;
       A() { }
       TA x;
   };
}

int main(int argc, char* argv[])
{
   NA::A<int>::CrearA();
}






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.