Constexpr no está permitido en la declaración de especialización plantilla de amigo?


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 casera bitset que ha estado compilando correctamente desde los días halcyon 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 trunk actual dan un error:

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

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

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

ACTUALIZACIÓN : archivado como error 65977 en Bugzilla.

Author: TemplateRex, 2015-04-26

1 answers

GCC se equivoca aquí.

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

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

Los especificadores se describen en la subcláusula 7.1 del estándar C++, y son un elemento de la gramática. Por lo tanto, cuando standard habla de un especificador foo que aparece en algún lugar, significa que el especificador apareció literalmente dentro del árbol de análisis del código fuente. El especificador 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 inline declara una función inline .

Hay otras dos maneras para declarar una función inline, sin usar un especificador 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 son implícitamente en línea (7.1.2).

Ninguno de estos dice que el comportamiento es como si un inline especificador estaban presentes, simplemente que la función es un función.

Entonces, ¿por qué existe esta regla?

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

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

El propósito de esto es permitir que las declaraciones de amigos sean ignoradas en la mayoría de los casos not no se les permite agregar "nueva información" a la entidad caso especial en el que están definiendo una función de amigo. (Esto a su vez permite que una implementación retrase 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 una declaración de un amigo especialización de un plantilla de función: si pudiera agregar información adicional, entonces las implementaciones no podrían retrasar el análisis de la definición de la 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, según (7.1.5)/1. Dado que no hay "nueva información" aquí, no hay necesidad de una restricción.

 33
Author: Richard Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-04 02:01:09