¿Pueden los constructores de plantillas de clases tener una lista de parámetros de plantilla redundante en c ++ 20?

Aug 21 2020

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++20esto 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

7 StoryTeller-UnslanderMonica Aug 21 2020 at 05:45

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 .