2011-12-10 10 views
5

¿Qué puedo hacer para que esto funcione:Plantilla referencia a sí misma en un argumento de plantilla

template<class C, class V, Test V::*> 
class Test { 
}; 

me da error del compilador:

unknown type name 'Test' 

Es una plantilla referencia a sí misma, por ahora, que doesn Parece posible. ¿Qué se podría hacer para que funcione?

EDIT:

Esto es lo que iba a necesitar para este. Quiero implementar un esquema de relación bidireccional (pensar padre-hijo) con el mínimo esfuerzo de codificación mínimo.

template <class O, class T, Reference<T, O, Reference O::*> T::* opposite> 
class Reference 
{ 
    T **data; 
    int count; 
public: 
    Reference(): data(new T*[N]), count(0) {} 
    ~Reference() {delete[] data;} 
    Reference &add(T *t) { 
     handleOtherSide(); 
     return link(t); 
    } 
    // a lot of stuff to implement this 
}; 

Esa es la clase de recopilación. Así es como se utilizaría:

class Partner 
{ 
public: 
    Reference<Partner, Address, &Address::partner> addresses; 
}; 

class Address 
{ 
public: 
    Reference<Address, Partner, &Partner::addresses> partner; 
}; 

Mi objetivo es tener todo lo necesario para referencia al trabajo ser suministrado como parámetro de plantilla, por lo que no hay necesidad de proporcionar a los constructores para las clases como socio y Dirección (actualmente proveo el puntero de miembro opuesto como arg de constructor, pero esto requiere que tenga constructores explícitos para las clases de participante). También necesitaría pasar o calcular un puntero de "propietario" a la clase de referencia. Dejé este problema aquí porque quiero centrarme en el aspecto de la plantilla de autorreferencia.

La manera más fácil de pensar en esto es boost :: bimap. Pero el problema con Bimap es que no quiero el bimap que lo contiene, sino solo la parte izquierda y derecha del mismo. bimap tampoco es factible porque llevaría a una sola bimap que gestione todas las asociaciones de una relación específica. Posiblemente mantendría una gran cantidad de objetos ralentizando las operaciones en él.

+2

¿Para qué es esto? Probablemente sea mucho más simple implementar esto de otra manera que la autorreferencia. – Jon

+5

Tuve que votar esta pregunta para sacar al OP de su 666 recuento de reputación. –

+2

¿Cuál es el objetivo que estás tratando de lograr con una plantilla recursiva, si no te importa que pregunte? – dasblinkenlight

Respuesta

1

El problema es que lo que yo quiero lograr no es posible en C++, al menos no con las plantillas y la cantidad de código y las clases que estoy con el objetivo de (léase: sola línea de código por cada miembro). Comienza con el compilador que necesita declaraciones avanzadas y tipos completamente definidos, lo que hace que los miembros con valores por cubo y los argumentos de la plantilla sean imposibles (en el caso de dependencias cíclicas). Entonces no es posible tener un puntero de miembro como una plantilla arg cuando la clase de ese miembro aún no está completamente definida. La causa principal de todo esto es cómo funciona el compilador: es de paso único. Y no hay nada que pueda hacer al respecto.

La solución es usar miembros de referencia por referencia o una clase base de estilo OO o un impulso :: cualquier contenedor de estilo para evitar las plantillas. Con los últimos 2 podría ser posible tener miembros con valores por valor.

2

¿Estás buscando algo como esto? Es plantilla no hace referencia a sí, pero se puede especificar la clase derivada como un tipo de plantilla para la clase base y clase base puede llamar a los métodos derivados etc .:

template< typename PType, typename PDerived > 
class TBase 
{ 
    //do stuff with TDerived 
public: 
    bool foo(void) 
    { 
    return (static_cast< PDerived* > (this)->bar()); 
    } 
}; 

template< typename PType > 
class TDerived : public TBase< PType, TDerived<PType> > 
{ 
    friend class TBase< PType, TDerived<PType> > ; 
    //do stuff 
protected: 
    bool bar(void) 
    { 
    return (true); 
    } 
}; 

EDIT: Una vez más, no estoy seguro de cuál es su última Gol. Aquí hay una solución para lo que creo que usted desea, o, al menos, alguna pista sobre lo que podría usar para implementar su diseño. El único requisito que puse es que tanto TAddress como TPartner tienen función con el mismo nombre. Ve si eso es lo que necesitas. En principio, puede crear una clase auxiliar y usar CRTP para acceder a la función de miembro a través de un puntero, pero no creo que realmente lo necesite.

template< typename PType1, typename PType2 > 
class TReference 
{ 
public: 
    int mFlag; 

    TReference() : 
    mFlag(0) 
    { 
    } 
    TReference(int fFlag) : 
    mFlag(fFlag) 
    { 
    std::cout << "Creating reference " << PType1::sName << " -> " << PType2::sName << "." << std::endl; 
    } 
    TReference< PType2, PType1 > AccessOpposite(void) 
    { 
    PType2 lTmp; 
    lTmp.Opposite(); 

    return TReference< PType2, PType1 > (-1); 
    } 
}; 

class TPartner; 

class TAddress 
{ 
public: 
    static const char* sName; 
    TReference< TAddress, TPartner > mRef; 

    void Opposite(void) 
    { 
    std::cout << sName << "::Opposite" << std::endl; 
    } 
}; 

class TPartner 
{ 
public: 
    static const char* sName; 
    TReference< TPartner, TAddress > mRef; 

    TReference< TAddress, TPartner > Opposite(void) 
    { 
    std::cout << sName << "::Opposite" << std::endl; 
    } 
}; 

const char* TAddress::sName = "TAddress"; 
const char* TPartner::sName = "TPartner"; 

int main(void) 
{ 
TAddress lAddress; 
TPartner lPartner; 

std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl; 

lPartner.mRef = lAddress.mRef.AccessOpposite(); 

std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl; 

return (0); 
} 
+0

Eso se ve bastante interesante y divertido. ¿Está bien no declarar miembro bar() en el nivel de clase base? –

+0

Sí, está bien debido a la forma en que se crean las instancias de las funciones de la plantilla. 'foo' no se creará una instancia hasta que se llame realmente en el código y para ese momento' TDerived' ya está definido. Busque el CRTP para obtener más información. – lapk

+0

Después de mirar esto por unos días debo decir cómo esto puede resolver mi problema me supera. Tal vez puedas adoptar mi ejemplo un poco más para que pueda ver la solución. –

Cuestiones relacionadas