Я написал следующую программу, которая компилируется с GCC и MSVC, но Clang ее отвергает. Программа:
int a[2] alignas(16) [5]; //GCC: Ok, Clang: No, MSVC: OK
Каково правильное поведение в соответствии с последним стандартом C++?
читая это может быть все в порядке. Анализ грамматики C++ немного сложен, поэтому не публикую ответ.
@NathanOliver noptr-declarator
не позволяет повторять [...]
, поэтому это выглядит неправильно. В грамматике может повторяться только attributespecifier-seq
.
Программа неправильно сформирована, потому что dcl.align не позволяет применять alignas(16)
к типу массива (int[2]
здесь), а через CWG2005 в вашем примере alignas(16)
относится к типу массива int[2]
.
Спецификатор выравнивания может применяться к переменной или элементу данных класса, но он не должен применяться к битовому полю, параметру функции или объявлению исключения ([кроме.handle]). Спецификатор выравнивания также может применяться к объявлению класса (в подробном спецификаторе типа ([dcl.type.elab]) или заголовке класса ([class]) соответственно). Спецификатор выравнивания с многоточием представляет собой расширение пакета ([temp.variadic]).
По сути, вы говорите, что объявления многомерных массивов невозможны...
Возьмите декларатор -> ptr-declarator -> noptr-declarator -> noptr-declarator [constant-expressionopt] атрибут-спецификатор-seqopt, а затем снова noptr-declarator [constant-expressionopt] атрибут-спецификатор-seqopt для внутреннего noptr-декларатора.
@ user17732522 Обновлено.
«Программа неправильно сформирована согласно dcl.align» — это настоящий скачок, это даже не подразумевается, она просто перечисляет некоторые места, где спецификатор может быть размещен, а некоторые — нет. . Ни один из них не указывает массивы, хотя массивы являются подтипом переменной или элемента данных класса, поэтому их также следует разрешить.
@Blindy Ваша логика ошибочна, потому что по вашей логике int
тоже должно быть разрешено, но это не так. См. этот комментарий, где член комитета C++ указал ту же причину неправильного формирования типа int
.
Если нет причин запрещать это (и все основные компиляторы, похоже, смогли реализовать int
как таковой, согласно комментарию, на который вы ссылаетесь), то, по моему мнению, это должно быть разрешено. Так что да, по крайней мере первая часть вашего комментария верна.
В позиции, которую вы написали alignas(16)
, это относится к типу внутреннего массива (а не к объявленной переменной). alignas(16)
нельзя применить к типу массива (или к любому типу вне объявленных классов), и поэтому, как поясняется CWG 2205, он имеет неправильную форму. Кланг прав.
alignas(16)
может применяться только к переменным, членам данных класса или объявлениям классов. Это вообще не применимо к типам, за последним исключением.
Важно отметить, что alignas
никогда не становится частью типа и не имеет никакого значения в системе типов. Это не спецификатор типа. Это потенциально отличается от некоторой реализации нестандартных атрибутов alignas
(например, __attribute__((aligned(...)))
), которые потенциально можно считать частью системы типов, аналогичной, например, спецификатор типа const
. В этом случае имело бы смысл применить его к типу в объявлении переменной, а не к самой переменной.
Позиции, в которых alignas
относится к самой переменной, кстати:
В начале объявления, где он относится к каждой сущности, объявленной этим объявлением (поскольку вы можете объявить несколько переменных и функций в одном объявлении):
alignas(16) int a[2][5];
Сразу после идентификатора декларатора, т. е. имени объявляемой переменной, и в этом случае оно относится только к этой переменной, если в одном объявлении объявлено несколько сущностей:
int a alignas(16) [2][5];
@NathanOliver В проблеме CWG говорится, что это неправильно, если это специально не разрешено, даже если оно грамматически правильное. eel.is/c++draft/dcl.align#1 указывает, где alignas
разрешено, что не включает типы (за одним упомянутым мной исключением).
@NathanOliver Каждый атрибут или alignas
относится к одному конкретному объекту. Эта сущность может быть, например, переменной или типом, но, что важно, это не одна и та же сущность. Объявлено, что переменная как сущность имеет определенный тип, который является другой сущностью. Сам тип может состоять из нескольких других типов, каждый из которых также является сущностью. Согласно eel.is/c++draft/dcl.array#3.sentence-2alignas
в позиции OP относится к типу массива, сформированному предыдущими скобками, а не к объявленной переменной.
@NathanOliver alignas
для типа, а не для объявленной переменной, не имеет смысла, поскольку типы не различаются по их выравниванию в системе типов, например. int
всегда имеет одинаковые требования к выравниванию. Не существует второго типа, называемого int alignas(16)
или чего-то в этом роде, который вел бы себя идентично int
, за исключением его подразумеваемого выравнивания. Это другое, кстати. чем некоторые компиляторы обрабатывают нестандартный __attribute__((alignas(...)))
или аналогичный, который может стать частью типа.
комментарии удалены, теперь я понимаю, к чему это идет. +1.
Выглядит неправильно, но два компилятора, принявшие это, удивляют.