c++ c++11 alignment alignas

¿Dónde puedo usar alignas() en C++ 11?



c++11 alignment (4)

En un esfuerzo por estandarizar mi código y hacerlo más portátil, reemplacé

#ifdef __GNUC__ typedef __attribute__((aligned(16))) float aligned_block[4]; #else typedef __declspec(align(16)) float aligned_block[4]; #endif

con

typedef float alignas(16) aligned_block[4];

en C ++ 11. Sin embargo, a gnu (4.8) no le gusta eso, pero se queja

test.cc:3:9: warning: attribute ignored [-Wattributes] typedef float alignas(16) aligned_block[4]; ^ test.cc:3:9: note: an attribute that appertains to a type-specifier is ignored

mientras que clang 3.2 no crea ninguna advertencia (incluso con -Weverything -Wno-c++98-compat -pedantic ). Entonces me pregunto si mi código anterior es correcto y, en términos más generales, dónde se pueden y no se pueden colocar las alignas() .

EDITAR (abr 2013) :

El artículo relevante de la norma es 7.6.2, en particular 7.6.2.1

Un especificador de alineación puede aplicarse a una variable oa un miembro de datos de clase, pero no se aplicará a un campo de bits, un parámetro de función, el parámetro formal de una cláusula catch (15.3), o una variable declarada con el registrar especificador de clase de almacenamiento. Un especificador de alineación también se puede aplicar a la declaración de una clase o tipo de enumeración. Un especificador de alineación con puntos suspensivos es una expansión de paquete (14.5.3).

como ya fue desenterrado por Red XIII. Sin embargo, no soy lo suficientemente experto como para saber lo que esto significa para mi prueba anterior.

Si el hecho de que clang acepta mi atributo significa algo, quizás valga la pena mencionar que cuando se intenta usar una directiva using lugar de un typedef , clang también se queja. Además, contrariamente a una afirmación en una versión anterior de esta pregunta, gcc no solo advierte, sino que ignora mi deseo de alineación.


Creo que acabas de colocar las alignas en la posición incorrecta. Si lo mueve directamente después del identificador, tanto GCC como Clang están contentos y aplican la alineación:

typedef float aligned_block alignas(16) [4]; typedef float aligned_block [4] alignas(16);

esto también es cierto si usa using , donde la diferencia también se vuelve más aparente. Aquí hay dos versiones que no son aceptadas por GCC (advertencia, alineación ignorada):

using aligned_block = float alignas(16)[4]; using aligned_block = float[4] alignas(16);

y aquí está el aceptado:

using aligned_block alignas(16) = float[4];

Creo que se aplica GCC

7.1.3 El especificador typedef [dcl.typedef]

2 Un typedef-name también puede ser introducido por una declaración de alias . El identificador que sigue a la palabra clave using convierte en un typedef-name y el atributo-especificador-seq opcional que sigue al identificador pertenece a ese typedef-name . Tiene la misma semántica que si fuera introducida por el especificador typedef . [...]

(énfasis mío)

Lo anterior es bastante claro para using , las reglas para typedef se distribuyen en varios párrafos, incluido al final de §8.3 / 1, donde se encuentra:

8.3 Significado de los declaradores [dcl.meaning]

1 [...] El atributo opcional -especificador-seq que sigue a un declarator-id pertenece a la entidad que se declara.

(otra vez, énfasis mío)

Actualización: la respuesta anterior se concentró en dónde se deben colocar las alignas , no en su significado exacto. Después de pensarlo un poco más, todavía creo que lo anterior debería ser válido. Considerar:

7.6.2 Especificador de alineación [dcl.align]

1 Un especificador de alineación puede aplicarse a una variable oa un miembro de datos de clase, pero no se aplicará a un campo de bits, un parámetro de función, una declaración de excepción (15.3) o una variable declarada con el almacenamiento de register especificador de clase Un especificador de alineación también puede aplicarse a la declaración o definición de una clase (en un especificador de tipo elaborado (7.1.6.3) o cabecera de clase (Cláusula 9), respectivamente) y a la declaración o definición de una enumeración ( en una opaque-enum-declaration o enum-head , respectivamente (7.2)). Un especificador de alineación con puntos suspensivos es una expansión de paquete (14.5.3).

Enumera los casos en los que se puede aplicar claramente y enumera los casos en los que claramente no se puede aplicar. El ejemplo de la pregunta anterior no es ninguno de los dos.

También se podría argumentar que el alias de tipo creado por typedef o using lleva la especificación de alineación como parte del tipo de alias. Este alias se puede usar para crear una variable, etc. según lo permitido por 7.6.2p1, pero no para crear una variable con register , etc.

En ese sentido, creo que el especificador de atributo se aplica (en el sentido de 7.6.2) de manera diferida y, por lo tanto, el ejemplo de OP debe seguir siendo válido cuando la especificación de alineación se coloca en el lugar sintácticamente correcto.


El borrador del estándar C ++ 11 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf dice al respecto (Alineación-especificador es de la forma alignas (asignación-expresión) )

7.6.2 Especificador de alineación [dcl.align]

1 Se puede aplicar un especificador de alineación a una variable oa un miembro de datos de clase, pero no se aplicará a un campo de bits, un parámetro de función, el parámetro formal de una cláusula catch (15.3) o una variable declarada con la clase de almacenamiento de registro especi fi cante. Un especificador de alineación también se puede aplicar a la declaración de una clase o tipo de enumeración. Un especificador de alineación con una elipsis es una expansión de paquete.

Encontré esta propuesta original http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf , dice:

El especificador de alineación no se convierte en parte del tipo, pero es posible crear un tipo de clase con variables miembro (s) alineado (s).

con este ejemplo:

// Wrong attempt: Listing 6) typedef double align_by<0x10000> hwDoubleVector; // Error! Void clear(hwDoubleVector &toClear, unsigned size);

Parece que es ilegal usarlo con typedef .


No puede aplicar una alineación a un typedef . En el modelo de C ++ de los especificadores de alineación, la alineación es una parte inseparable del mismo tipo, y un typedef no crea un nuevo tipo (solo proporciona un nuevo nombre para un tipo existente) por lo que no es significativo aplicar un especificador de alineación en una declaración typedef .

Desde [dcl.align] (7.6.2) p1 :

Un especificador de alineación se puede aplicar a una variable o a un miembro de datos de clase [...]. Un especificador de alineación también puede aplicarse a la declaración o definición de una clase (en un especificador de tipo elaborado (7.1.6.3) o cabecera de clase (Cláusula 9), respectivamente) y a la declaración o definición de una enumeración ( en una opaque-enum-declaration o enum-head , respectivamente (7.2)).

Estos son los únicos lugares donde el estándar dice que se puede aplicar un especificador de alineación ( alignas(...) ). Tenga en cuenta que esto no incluye las declaraciones typedef ni alias-declaration s.

Por [dcl.attr.grammar] (7.6.1) p4 :

Si un atributo-especificador-seq que pertenece a alguna entidad o enunciado contiene un atributo que no está permitido aplicar a esa entidad o enunciado, el programa está mal formado.

Esta redacción estaba destinada a aplicarse tanto a las alignas como a las otras formas de atributo que pueden aparecer dentro de un atributo-especificador-seq , pero no se actualizó correctamente cuando la alineación pasó de ser un atributo "real" a ser un tipo diferente de atributo- especificador-seq .

Entonces: se supone que su código de ejemplo que usa alignas está mal formado. El estándar de C ++ actualmente no dice esto explícitamente, pero tampoco permite el uso, por lo que en la actualidad daría como resultado un comportamiento indefinido (porque el estándar no define ningún comportamiento para él).


Tratar:

typedef float alignas(16) aligned_block[4];