and c++ templates c++11 g++ constexpr

and - constexpr in c++



¿Constexpr no está permitido en la declaración de especialización de plantillas de amigos? (1)

GCC está equivocado aquí.

Todas las referencias son a N4431, el último WD de C ++.

[tl; dr: Hay una diferencia entre una función que está en línea (o más precisamente, que es una función en línea , como se define en 7.1.2 / 2) y que se declara con el especificador en inline . El especificador constexpr hace una función en línea, pero no es un especificador en inline .]

Los especificadores se describen en la subcláusula 7.1 del estándar de C ++, y son un elemento de la gramática. Por lo tanto, siempre que las conversaciones estándar sobre un especificador foo aparezcan en algún lugar, significa que el especificador apareció literalmente dentro del árbol de código fuente (parse) del código fuente. El especificador en inline es un especificador de función , descrito en la subcláusula 7.1.2, y su efecto es hacer que una función sea una función en línea. (7.1.2) / 2:

Una declaración de función (8.3.5, 9.3, 11.3) con un especificador en inline declara una función en línea .

Hay otras dos maneras de declarar una función en línea, sin usar un especificador en inline . Uno se describe en (7.1.2) / 3:

Una función definida dentro de una definición de clase es una función en línea.

El otro se describe en (7.1.5) / 1:

Las funciones constexpr y los constructores constexpr están implícitamente en línea (7.1.2).

Ninguno de estos dice que el comportamiento es como si un especificador en inline estuviera presente, simplemente que la función es una función en línea.

Entonces, ¿por qué existe esta regla?

Hay una forma más simple de esta regla en (7.1.2) / 3:

Si el especificador en inline se utiliza en una declaración de amistad, esa declaración será una definición o la función se habrá declarado previamente en línea.

El objetivo de esto es permitir que se ignoren las declaraciones de amigos en la mayoría de los casos, no se les permite agregar "nueva información" a la entidad con la que se hacen amigos, excepto en el caso especial en el que definen una función de amigo. (Esto a su vez permite que una implementación demore el análisis de una definición de clase hasta que sea "necesaria"). Así también vemos, en (8.3.6) / 4:

Si una declaración de amigo especifica una expresión de argumento por defecto, esa declaración será una definición y será la única declaración de la función o plantilla de función en la unidad de traducción.

Y lo mismo se aplica a la declaración de una especialización de amigo de una plantilla de función: si pudiera agregar información adicional, las implementaciones no podrían demorar el análisis de la definición de clase.

Ahora, tenga en cuenta que este razonamiento no se aplica a constexpr : si el especificador constexpr aparece en cualquier declaración de una función, debe aparecer en cada declaración, por (7.1.5) / 1. Como no hay "nueva información" aquí, no hay necesidad de una restricción.

Estoy portando una base de código C ++ 14- constexpr de Clang a la última g ++ - 5.1. Considere el siguiente fragmento de código reducido de una clase de bitset cosecha bitset que se ha estado compilando correctamente desde los días felices de Clang 3.3 (¡casi 2 años ahora!)

#include <cstddef> template<std::size_t> class bitset; template<std::size_t N> constexpr bool operator==(const bitset<N>& lhs, const bitset<N>& rhs) noexcept; template<std::size_t N> class bitset { friend constexpr bool operator== <>(const bitset<N>&, const bitset<N>&) noexcept; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <-- error from this piece }; template<std::size_t N> constexpr bool operator==(const bitset<N>& /* lhs */, const bitset<N>& /* rhs */) noexcept { return true; } int main() {}

Ejemplo en vivo en Wandbox. Sin embargo, g ++ - 5.1 y la versión actual del enlace dan un error:

''constexpr'' no está permitido en la declaración de especialización de plantilla de amigo

Pregunta : ¿se trata de un error conocido de g ++ o Clang no se ajusta al último estándar?

Nota : lo anterior solo usa las características de constexpr estilo C ++ 11, ya que no hay modificaciones dentro del operator== , por lo que parece una extraña interferencia entre plantillas, amigos y constexpr.

ACTUALIZACIÓN : archivado como error 65977 en Bugzilla.