2011-12-26 27 views
6

Old GCC 4.1.2 accepts, y nuevo GCC 4.5.1 accepts, el siguiente programa.¿Es válido escribir la lista de parámetros del tipo de plantilla en una declaración de constructor?

¿Pero es realmente correcto? ¿Qué dice la norma sobre declarar un constructor con el parámetro de plantilla del tipo como este?

(Me parece interesante que yo no estoy autorizado a do the same in the out-of-line definition.)

#include <iostream> 
template <typename T> 
struct Foo { 
    Foo<T>(); // <--- 
}; 

template <typename T> 
Foo<T>::Foo() { 
    std::cout << ":)"; 
} 

int main() { 
    Foo<int> f; 
} 

La razón que pido es que se propuso en los comentarios sobre this answer que GCC puede ser un error aquí.

+0

FWIW, compila y ejecuta en GCC 4.6.1 también. – Mat

+3

Presumiblemente debido a 12.1/1: "La sintaxis usa ... el nombre de clase del constructor ...", esta pregunta equivale a "es' Foo '¿el nombre de clase?" –

+0

@SteveJessop: ... "y, de ser así, ¿por qué no se acepta en la definición?" –

Respuesta

3

voy a poner una copia de correo de una posible DR poco me envió en Navidad aquí

está bien formado el siguiente código?

template<typename T> 
struct A { 
    A<T>(); 
}; 

Los varios compiladores que he probado (sonido metálico, g ++ y conline comeau) aceptar esto. De hecho 12.1 no prohíbe esto (A<T> es un nombre de esa clase y no es un nombre typedef), pero 8.3p1 dice

un rotundo-id ocurriendo en un declarador-id será un simple identificador excepto para la declaración de algunas funciones especiales (12.3, 12.4 , 13.5) ...

un constructor es una función miembro especial, pero la lista de referencias cruzadas no incluye 12.1. ¿Eso significa que el código anterior está mal formado? ¿O es esto una omisión accidental?

Si hace lo mismo en una definición fuera de línea, intentará pasar argumentos de plantilla a un constructor. Este es un código válido

struct A { 
    template<typename T> A(); 
}; 

template<> A::A<int>() { } 

La especificación dice que cuando el nombre de la clase inyectada se utiliza en un nombre calificado cuando se mira en el ámbito de la clase (al igual que en A::A), a continuación, cuando la búsqueda de nombres acepta la función nombres/constructor , la referencia del nombre de clase inyectado será traducida para ser resuelta al constructor (es) de esa clase (si el contexto de búsqueda de nombre solo acepta tipos, entonces el nombre seguirá siendo el nombre de clase inyectado, y denotará el tipo de clase). Después de A::A, la búsqueda del nombre está completa y proporciona el constructor. El <int> solo se puede analizar como una lista de argumentos de plantilla. Si no hay una plantilla entre sus constructores, su código no será válido.

+0

El primer párrafo parece implicar que el código dado es válido. Pero errr ... el OP preguntó sobre un constructor regular de una clase de plantilla, no sobre un constructor con plantilla. ('A :: A()' i.s.o. 'A :: A()'). – xtofl

+0

@xtofl Creo que malinterpretaste mi respuesta. Después de la copia de mi correo, elaboré la parte de la pregunta de OP "(Me parece interesante que no se me permita hacer lo mismo en la definición fuera de línea)". El primer párrafo (la cita que representa mi correo) implica que el código es aceptado por GCC, clang y el compilador en línea comeau. No implica que el código sea válido. –

+0

Lo siento; Soy un tipo inteligente, pero ¿puedes resumir esto para mí? –

Cuestiones relacionadas