2012-01-23 17 views
50

Digamos que estoy creando una clase para un árbol binario, BT, y tengo una clase que describe un elemento del árbol, BE, algo así comoPlantilla de clase con amigo de clase de plantilla, ¿qué está pasando realmente aquí?

template<class T> class BE { 
    T *data; 
    BE *l, *r; 
public: 
... 
    template<class U> friend class BT; 
}; 

template<class T> class BT { 
    BE<T> *root; 
public: 
... 
private: 
... 
}; 

Esto parece funcionar; Sin embargo, tengo preguntas sobre lo que está sucediendo debajo.

originalmente trató de declarar el amigo como

template<class T> friend class BT; 

sin embargo, parece necesario utilizar U (o algo distinto de T) aquí, ¿por qué es esto? ¿Implica que cualquier particular BT es amigo de cualquier clase en particular BE?

La página de IBM en plantillas y amigos tiene ejemplos de diferentes tipos de relaciones de amigos para funciones pero no para clases (y adivinar que la sintaxis aún no ha convergido en la solución). Preferiría entender cómo obtener las especificaciones correctas para el tipo de relación de amigo que deseo definir.

Respuesta

76
template<class T> class BE{ 
    template<class T> friend class BT; 
}; 

No está permitido porque los parámetros de la plantilla no se pueden ensombrecer. Las plantillas anidadas deben tener diferentes nombres de parámetros de plantilla.


template<typename T> 
struct foo { 
    template<typename U> 
    friend class bar; 
}; 

Esto significa que bar es un amigo de foo independientemente de argumentos de plantilla bar 's. bar<char>, bar<int>, bar<float>, y cualquier otro bar serían amigos de foo<char>.


template<typename T> 
struct foo { 
    friend class bar<T>; 
}; 

Esto significa que bar es un amigo de foo cuando bar 's argumento de plantilla coincide foo' s. Solo bar<char> sería amigo de foo<char>.


En su caso, friend class bar<T>; debería ser suficiente.

+2

esta construcción en mi código amigo clase BT genera un error para el amigo línea de error : 'BT' no es una plantilla aunque se haya declarado más tarde como plantilla clase BT { ... } –

+1

Así que el secreto es que necesitaba reenviar declarar BT para usar la clase de amigo BT ; línea en el BE, pero no para la plantilla clase de amigo BT ;. ¡Gracias por la ayuda! –

+16

Para ser más específicos: debe reenviar declarar 'plantilla clase BT;' _antes de la definición de BE, y luego usar 'clase de amigo BT ;' _inside_ la clase BE. –

-1

En mi caso esta solución funciona correctamente:

template <typename T> 
class DerivedClass1 : public BaseClass1 { 
    template<class T> friend class DerivedClass2; 
private: 
int a; 
}; 

template <typename T> 
class DerivedClass2 : public BaseClass1 { 
    void method() { this->i;} 
}; 

espero que será útil.

+5

¿Cómo se supone que esa solución funciona correctamente cuando está sombreando los parámetros de la plantilla y de lo contrario no permite que el amigo de DerivedClass2 acceda a DerivedClass1? – kornman00

1

con el fin de hacer amistad con otra del mismo tipo de estructura:

template<typename T> 
struct Foo 
{ 
    template<typename> friend struct Foo; 
}; 

nota de que en template<typename> friend struct Foo; no se debe escribir T después typename/class; de lo contrario, causaría un error de sombreado de parm de plantilla.

+3

Por favor, mejore su respuesta. – swiftBoy

1

No es necesario nombrar los parámetros para que pueda obtener un menor número de puntos de fallo si refactorización:

 template <typename _KeyT, typename _ValueT> class hash_map_iterator{ 
     template <typename, typename, int> friend class hash_map; 
     ... 
Cuestiones relacionadas