¿Pueden los constructores de plantillas de clases tener una lista de parámetros de plantilla redundante en c ++ 20?
Hasta donde yo sé, el siguiente código :
template<typename T>
struct S {
S<T>();
};
está bien formado, a pesar <T>
de que la declaración del constructor es redundante.
Sin embargo, en gcc trunk (pero no en gcc10.2), -std=c++20
esto da un error:
error: expected unqualified-id before ')' token
3 | S<T>();
^
El código se compila en clang trunk con -std=c++20
. ¿Es esto un error o es un cambio importante en c ++ 20 que aún no se ha implementado en todos los compiladores?
Respuestas
De hecho, hubo un cambio. Está documentado en la sección de compatibilidad del borrador de C ++ 20.
[diff.cpp17.class]
2 Subcláusulas afectadas : [class.ctor] y [class.dtor]
Cambio : Un simple-template-id ya no es válido como declarator-id de un constructor o destructor.
Justificación : Elimine la opción potencialmente propensa a errores para la redundancia.
Efecto sobre la característica original : Es posible que el código C ++ 2017 válido no se compile en esta Norma Internacional. Por ejemplo:template<class T> struct A { A<T>(); // error: simple-template-id not allowed for constructor A(int); // OK, injected-class-name used ~A<T>(); // error: simple-template-id not allowed for destructor };
Específicamente, la redacción delta es la siguiente:
n4659 - Borrador estándar de C ++ 17 - [class.ctor]
1 Los constructores no tienen nombre. En una declaración de un constructor, el declarador es un declarador de función de la forma
ptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seq
donde el ptr-declarator consiste únicamente en una expresión-id, un atributo-especificador-seq opcional y paréntesis opcionales alrededor, y la expresión-id tiene una de las siguientes formas:
- en una declaración-miembro que pertenece a la especificación-miembro de una clase pero que no es una declaración amiga, la expresión-id es el nombre-clase-inyectado de la clase que lo encierra inmediatamente;
- en una declaración-miembro que pertenece a la especificación-miembro de una plantilla de clase pero no es una declaración amiga, la expresión-id es un nombre de clase que nombra la instanciación actual de la plantilla de clase que la encierra inmediatamente; o
n4861 - Borrador estándar de C ++ 20 - [class.ctor]
1 Un constructor es introducido por una declaración cuyo declarador es un declarador de función ([dcl.fct]) de la forma
ptr-declarator ( parameter-declaration-clause ) noexcept-specifier attribute-specifier-seq
donde el ptr-declarator consiste únicamente en una expresión-id, un atributo-especificador-seq opcional y paréntesis opcionales alrededor, y la expresión-id tiene una de las siguientes formas:
- en una declaración-miembro que pertenece a la especificación-miembro de una clase o plantilla de clase pero no es una declaración de amigo ([class.friend]), la expresión-id es el nombre-clase-inyectado ([class.pre]) de la entidad envolvente inmediata o
Como puede ver, la redacción cambió. C ++ 20 ahora requiere el nombre de clase inyectado al declarar un constructor para una plantilla de clase. S<T>
es un identificador de plantilla simple que nombra una especialización. Dentro de una plantilla, el nombre de la clase inyectada es simplemente S
.
Esto es parte de abordar CWG 2237 .