2012-10-09 45 views
7

Tengo una pregunta para la amistad de plantilla específica en C++. en el libro de C++ cartilla, la amistad plantilla específica se escribe así:Plantilla específica Amistad en C++

template <class T> class Foo3; 
template <class T> void templ_fcn3(const T&); 
template <class Type> class Bar { 
    // each instantiation of Bar grants access to the 
    // version of Foo3 or templ_fcn3 instantiated with the same type 
    friend class Foo3<Type>; 
    friend void templ_fcn3<Type>(const Type&); 
    // ... 
}; 

El punto especial es que hay

<Type> 

después de que el nombre de la clase o función en el amigo comunicado.

Sin embargo, en la práctica, si escribo esto:

template <class Type> class T_CheckPointer; 
template <class T> T_CheckPointer<T> operator+(const T_CheckPointer<T> &, const size_t n); 

template <typename Type> 
class T_CheckPointer { 

    // Specific Template Friendship 
    friend T_CheckPointer<Type> 
    operator+ <Type> (const T_CheckPointer<Type> &, const size_t n); 

// other code... 

} 

No será un error durante ejemplificaciones para la función de plantilla.

Y si cambio

// Specific Template Friendship 
friend T_CheckPointer<Type> 
    operator+ <Type> (const T_CheckPointer<Type> &, const size_t n); 

a

// Specific Template Friendship 
friend T_CheckPointer<Type> 
    operator+ <> (const T_CheckPointer<Type> &, const size_t n); 

suprimiendo la palabra tipo después de que el nombre de la función, entonces todo estará bien.

¿Alguien puede decirme el motivo?


Para información, no es el mensaje error cuando llamo

int iarr[] = {1, 2, 3, 4}; 
T_CheckPointer<int> itcp(iarr, iarr+4); 

mensaje de error:

/usr/include/c++/4.4/bits/stl_iterator_base_types.h: In instantiation of ‘std::iterator_traits<int>’: 
/usr/include/c++/4.4/bits/stl_iterator.h:96: instantiated from ‘std::reverse_iterator<int>’ 
../Classes/T_CheckPointer.hpp:31: instantiated from ‘T_CheckPointer<int>’ 
../PE16.cpp:520: instantiated from here 
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:127: error: ‘int’ is not a class, struct, or union type 
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:128: error: ‘int’ is not a class, struct, or union type 
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:129: error: ‘int’ is not a class, struct, or union type 
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:130: error: ‘int’ is not a class, struct, or union type 
/usr/include/c++/4.4/bits/stl_iterator_base_types.h:131: error: ‘int’ is not a class, struct, or union type 
+0

¿Cuál es el mensaje de error? – enobayram

+0

@enobayram, gracias por su atención, los he puesto en el artículo. – Tianyi

+0

¿Podría proporcionar un ejemplo ** mínimo ** (que compila en, por ejemplo,Ideone) que muestra el problema? ¿Y trataste de actualizar a gcc 4.7? – TemplateRex

Respuesta

4

He aquí un ejemplo mínimo:

template<typename T> struct U { typedef typename T::X X; }; 
template<typename T> void foo(typename U<T>::X); 

template<typename T> struct S; 
template<typename T> void foo(S<T>); 
template<typename T> struct S { friend void foo<T>(S<T>); }; 

template struct S<int>; 

La razón por la que falla la declaración friend es que al proporcionar una lista completa de argumentos de plantilla, solicita al compilador que especialice todas las plantillas de funciones disponibles y elija la que mejor se adapte a la firma. La especialización de la primera definición de foo da como resultado la especialización U con un argumento que da como resultado un programa mal formado.

Si, por el contrario, omite el argumento de la plantilla, se deducirá de los argumentos. Como dicha deducción del argumento de la plantilla se realiza de acuerdo con 14.8.2 [temp.deduct], y en particular se aplica 14.8.2p8, lo que significa que la falla de sustitución en la especialización de U no es un error (SFINAE).

Esta es una buena razón para omitir los argumentos de la plantilla en cualquier lugar que puedan deducirse del contexto (por ejemplo, aquí los tipos de parámetros de función o de operador). Tenga en cuenta que aún necesita proporcionar los corchetes <> para asegurarse de que el operator + se lea como id-plantilla (14.5.4 [temp.friend]).

+0

+1 ¡Esta es una gran respuesta! También tenga en cuenta que los corchetes '<>' son para evitar que se seleccionen funciones que no sean de plantilla en lugar de funciones de plantilla. Ver esta antigua columna de Herb Sutter http://www.drdobbs.com/befriending-templates/184403853 – TemplateRex

+0

+1 ¡Muchas gracias por su respuesta! Tu respuesta es muy clara. @ecatmur – Tianyi