vectors variable length array c++ c++11 using-directives stdarray

c++ - variable - Usando std:: array y usando "array" como nombre



variable length array c++ (1)

No encontré nada que diga que el comportamiento que descubriste está bien, pero he encontrado que sigue, que podría estar afirmando lo contrario.

Cuando el nombre de una plantilla de miembro de especialización aparece después. o -> en una expresión postfix o después de un especificador de nombre anidado en una id-calificada, y la expresión de objeto de la expresión-postfix depende del tipo o el especificador de nombre anidado en la id-calificada se refiere a tipo dependiente, pero el nombre no es un miembro de la instanciación actual (14.6.2.1), el nombre de la plantilla de miembro debe ir precedido por la plantilla de palabra clave. De lo contrario, se asume que el nombre nombra una no-plantilla.

[ Example: struct X { template<std::size_t> X* alloc(); template<std::size_t> static X* adjust(); }; template<class T> void f(T* p) { T* p1 = p->alloc<200>(); // ill-formed: < means less than T* p2 = p->template alloc<200>(); // OK: < starts template argument list T::adjust<100>(); // ill-formed: < means less than T::template adjust<100>(); // OK: < starts template argument list } — end example ]

Puede evitar la identificación como ya se sugirió colocando los elementos comparados entre paréntesis. Se romperá la array< nombres array<

return (lhs.val.array) < (rhs.val.array);

Simplifiquemos un poco más el código y eliminemos todos los elementos incluidos que podrían estar ocultando lo que está sucediendo. Comenzaré con el código original que aún no se compila.

#include <cstddef> // needed for size_t //using std::array; brings following two lines into your code: template< class T, std::size_t N > struct array; template <typename X> struct A { struct value_t { int array; }; value_t val = {}; friend bool operator<(const A& lhs, const A& rhs) { return (lhs.val.array < rhs.val.array); } };

Y ahora vamos a mover struct value_t { int array; }; struct value_t { int array; }; fuera de la definición de plantilla:

#include <cstddef> // needed for size_t //using std::array; brings following two lines into your code: template< class T, std::size_t N > struct array; struct value_t { int array; }; template <typename X> struct A { value_t val = {}; friend bool operator<(const A& lhs, const A& rhs) { return (lhs.val.array < rhs.val.array); } };

Entonces al incluir <array> en su código, trajo una matriz de plantillas en su código como se muestra aquí. En la versión con value_t fuera de la plantilla hay una array<T> y una array miembro. Estas son cosas diferentes y por lo tanto sin ningún conflicto.
Cuando coloca value_t dentro de la plantilla, el compilador inicia sus intentos de expandir lo que proviene de esa plantilla. Intenta hacerlo con la matriz de miembros que no debería ocurrir como se especifica en el estándar.

De todos modos, parece un error en GCC, porque cuando aparece en la expresión lhs.val.array , debe tratarse como plantilla solo cuando está prefijado con la plantilla de palabra clave lhs.val.template array<

Y sí, usar el mismo nombre en diferentes contextos es perfectamente correcto, a menos que sea una de las palabras reservadas, que no sea la matriz. Pero ten cuidado con este uso de los nombres. Me resulta al menos confuso usar la matriz de nombres para la variable que contiene un solo entero. El nombre ya sugiere que habrá más de uno.

En mi biblioteca C ++ JSON, recientemente tuve una regresión con GCC7 . Desnudé el código afectado y espero entender el error.

El código

Considere este encabezado myclass.hpp :

#pragma once template <typename X> struct A { struct value_t { X array; }; static A array() { return A(); } friend bool operator<(const A& lhs, const A& rhs) noexcept { return lhs.val.array < rhs.val.array; } value_t val = {}; };

Como ve, usé el nombre "array" como nombre de variable miembro en struct value_t , como nombre de una función estática. Luego incluí el encabezado en el siguiente archivo:

#include <array> using std::array; // note this! #include "myclass.hpp" int main() {}

El problema

El código se compila con GCC6 y Clang5 (usando -std=c++11 ), pero GCC7 informa:

In file included from example.cpp:3:0: myclass.hpp: In function ''bool operator<(const A<X>&, const A<X>&)'': myclass.hpp:19:40: error: wrong number of template arguments (1, should be 2) return lhs.val.array < rhs.val.array; ^~~~~ In file included from example.cpp:1:0: /usr/local/Cellar/gcc/7.1.0/include/c++/7.1.0/array:94:12: note: provided for ''template<class _Tp, long unsigned int _Nm> struct std::array'' struct array ^~~~~ make: *** [all] Error 1

Parece como si el analizador lhs.val.array la "matriz" en lhs.val.array como std::array y tratara lo siguiente < como el inicio de una lista de plantillas.

El código se puede compilar si hago cualquiera de los cambios a continuación:

  • Eliminar el using std::array; o muévalo detrás de #include "myclass.hpp" .
  • Cambiar return lhs.val.array < rhs.val.array; para return (lhs.val.array) < rhs.val.array; .

Además, cualquiera de los compiladores falla si elimino la función static A array() ...

Mis preguntas

  • ¿Es el código correcto en primer lugar? ¿Puedo usar "array" como nombre incluso si uso using std::array; ?
  • Si el código es correcto, ¿es esto un error en GCC7?