sirven que puntero plantillas plantilla para los clases clase c++ templates c++14 language-lawyer constexpr

que - plantillas en c++



Miembro de la clase constestado con plantillas estáticas (1)

Desde n4140

§ 9.2.2 [class.mem] ( Énfasis mío)

Una clase se considera un tipo de objeto completamente definido (3.9) (o tipo completo) al cierre } del especificador de clase . Dentro de la especificación de miembro de la clase, la clase se considera completa dentro de los cuerpos de funciones, los argumentos por defecto, las declaraciones de uso que introducen constructores heredadores (12.9), las especificaciones de excepción y los inicializadores ortográficos o equivalentes para los miembros de datos no estáticos (incluidos tales cosas en clases anidadas). De lo contrario, se considera como incompleto dentro de su propia especificación de miembro de clase .

Clang y GCC son correctos. La clase no se considera completa cuando declara su miembro de static constexpr , por lo que no puede construirlo. Esta es la razón por la cual mover la definición de Bar out o eliminar los trabajos de static constexpr (porque se considera completa al definir miembros no estáticos)

Para aclarar, especialmente teniendo en cuenta esta pregunta: Constestador estático miembro de una clase interna

El standardese que cité arriba significa básicamente que a menos que se especifique lo contrario, una clase se considera incompleta en sí misma * . Un inicializador de static constexpr static , constexpr o static constexpr no cae dentro de la porción especificada de otra manera , y por lo tanto no podemos usar nada declarado dentro de la clase, que incluye un tipo de clase anidada.

* lo que significa que no puede usarlo o miembros de él dentro de la declaración de la clase. La excepción más conocida es la función miembro.

Tengo la siguiente clase de muestra Foo con Bar clase anidada y todo es constexpr :

class Foo { private: template <typename T> struct Bar { constexpr Bar(){} constexpr int DoTheThing() const { return 1; } }; public: constexpr static auto b = Bar<int>{}; constexpr Foo() {} constexpr int DoTheThing() const { return b.DoTheThing(); } };

Y quiero probar que al llamar a Foo::DoTheThing devuelve 1:

int main() { constexpr Foo f; static_assert(f.DoTheThing() == 1, "DoTheThing() should return 1"); }

GCC y Clang se quejan aquí, pero MSVC no lo hace

GCC dice:

error: constexpr Foo::Bar<T>::Bar() [with T = int] utilizado antes de su definición

constexpr static auto b = Bar<int>{};

Y Clang :

error: constexpr variable b debe inicializarse mediante una expresión constante

constexpr static auto b = Bar<int>{};

No puedo decir si el estándar no permite esto, pero supongo que de alguna manera b es un tipo incompleto.

Lo que hace las cosas más interesantes es que puedo hacer que GCC y Clang se comporten si constexpr el constexpr o si muevo la definición de Bar fuera de Foo .

¿Cuál de estos compiladores es el correcto?

Tenga en cuenta que esta pregunta se inspiró en lo siguiente:

  • Contorno simple LookUpTable en C ++ 14 (mi problema es una parte del problema de esta pregunta sin respuesta)
  • La estructura anidada se rompe a pesar de ser idéntica a las globales (esto parece proporcionar una idea de lo que está sucediendo)