2010-09-02 10 views
6

Considere este código:ADL y amigo inyección

template <int N> 
struct X 
{ 
friend void f(X *) {} 
}; 

int main() 
{ 
f((X<0> *)0); // Error? 
} 

compiladores parecen no estar de acuerdo en gran medida. (MSVC08/10 dice que no, GCC < 4.5 dice que sí, pero 4.5 dice que no, sun 5.1 dice sí, intel 11.1 dice que sí también, pero Comeau dice que no (ambos son EDG)).

De acuerdo con "plantillas de C++ - La guía completa":

... se supone que una llamada que implica una búsqueda de amigos en clases asociadas realmente causa la clase a una instancia .. . A pesar de que fue claramente intencionado por aquellos que escribieron el estándar C++, no es claramente explicado en el estándar.

No pude encontrar la sección correspondiente en la norma. ¿Alguna referencia?

considerar esta variación:

template <int N> 
struct X 
{ 
template <int M> 
friend void f(X<M> *) {} 
}; 

template <> 
struct X<0> 
{ 
}; 

int main() 
{ 
X<1>(); 
f((X<0> *)0); // Error? 
} 

La cuestión clave aquí es la función de carnero viable inyectado por X<1> debe ser visible durante la ADL para X<0>? ¿Están asociados? Todos los compiladores mencionados anteriormente aceptan este código, a excepción de Comeau que solo lo acepta en modo relajado. No estoy seguro de lo que el estándar tiene que decir sobre esto tampoco.

¿Cuál es su opinión sobre eso?

Respuesta

4

La norma dice en 14.7.1/4

Una especialización de plantilla de clase se instancia implícitamente, si el tipo de clase se utiliza en un contexto que requiere un tipo de objeto definido por completo, o si la integridad del tipo de clase afecta a la semántica Del programa; en particular, si una expresión cuyo tipo es una especialización de plantilla de clase está involucrada en la resolución de sobrecarga, conversión de puntero, conversión de puntero a miembro, la especialización de plantilla de clase se instancia de manera implícita (3.2);

Tenga en cuenta que Vandervoorde realizó una issue report here, y el comité encontró

El estándar especifica ya que esto crea un punto de ejemplificación.

Para su segundo caso, debe tener en cuenta las clases y los espacios de nombres asociados del argumento f(X<0>*). Estos son, dado que esto es un puntero a una especialización de plantilla de clase (tenga en cuenta que "template-id" a continuación no es del todo correcto - C++ 0x corrigió eso para usar el término correcto) y también un puntero a una clase (esta división confusa también se corrigió en C++ 0x - enumera estos dos casos en un punto).

  • Si T es una plantilla-id, sus espacios de nombres y clases asociadas son el espacio de nombres en el que la plantilla es definido; [... mucho ruido ...]

  • Si T es un tipo de clase (incluidos los sindicatos), sus clases asociadas son: la clase en sí; la clase de la que es miembro, si la hay; y sus clases base directas e indirectas. Sus espacios de nombres asociados son los espacios de nombres en los que se definen sus clases asociadas.

Así que para resumen, tenemos clases como asociados son X<0> y los espacios de nombres asociados son el espacio de nombres global. Ahora las funciones amigas que son visibles son

  • Cualquier funciones friend espacio de nombres de alcance declarados en las clases asociadas son visibles dentro de sus respectivos espacios de nombres, incluso si no son visibles durante una búsqueda ordinaria

No hay una función de amigo declarada en X<0> por lo que la declaración de función de amigo no está visible cuando se busca en el espacio de nombres global. Tenga en cuenta que X<0> es un tipo de clase completamente diferente que X<1>. La instanciación implícita de X<1> que haga allí no tiene ningún efecto en esta llamada; simplemente agrega un nombre no visible en el espacio de nombre global que hace referencia a una función de amigo de la clase X<1>.

+0

En caso de que el primer ejemplo sea compilable, entonces? – jpalecek

+0

Gracias :) Esto es más o menos lo que sospechaba. ¿Cómo es que tantos compiladores se equivocan con el segundo caso? Además, lo agradecería si pudiera dar referencias al estándar para las otras citas también. – uj2

+0

@ uj2 bueno, al menos clang se ve bien en comparación con GCC. Rechaza correctamente el segundo caso. Especialmente GCC tiene bastantes problemas de conformidad con la plantilla, así que esto no me sorprende. ¿Cuáles son las otras citas para las que intenta encontrar párrafos estándar? –