35

コードを標準化し、移植性を高めるために、次のように置き換えました。

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

typedef float alignas(16) aligned_block[4];

C++11 で。しかし、gnu (4.8) はそれを好まず、不平を言っています。

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

一方、clang 3.2 は警告を生成しません (たとえ があっても-Weverything -Wno-c++98-compat -pedantic)。したがって、上記のコードが正しいかどうか、より一般的には、配置できる場所alignas()と配置できない場所があるのではないかと思います。

編集(2013年4月)

標準の関連記事は 7.6.2、特に 7.6.2.1 です。

アライメント指定子は、変数またはクラス データ メンバーに適用できますが、ビット フィールド、関数パラメーター、catch 句の仮パラメーター (15.3)、または で宣言された変数には適用してはなりません。ストレージ クラス指定子を登録します。アライメント指定子は、クラスまたは列挙型の宣言にも適用できます。省略記号付きの配置指定子は、パック展開 (14.5.3) です。

すでにレッドXIIIによって掘り出されたように。ただし、上記のテストでこれが何を意味するかを知るには、私は十分な専門家ではありません。

usingclang が私の属性を受け入れるという事実が何かを意味する場合、 の代わりにディレクティブを使用しようとするとtypedef、clang も文句を言うことに言及する価値があるかもしれません。また、この質問の以前のバージョンのステートメントとは対照的に、gcc は警告するだけでなく、実際にアライメントに対する私の希望を無視します。

4

4 に答える 4

33

alignas間違った位置に置いただけだと思います。識別子の直後に移動すると、GCC と Clang の両方が満足して配置を適用します。

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

これは、 を使用する場合にも当てはまりusing、違いもより明確になります。GCC で受け入れられない2 つのバージョンを次に示します(警告、配置は無視されます)。

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

そしてここに受け入れられたものがあります:

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

GCCが当てはまると思います

7.1.3 typedef 指定子 [dcl.typedef]

2 typedef-nameは、 alias-declarationによって導入することもできます。キーワードに続く識別子は typedef-name になり、識別子続くオプションattribute - specifier -seqはそのtypedef-nameに属します。指定子によって導入された場合と同じセマンティクスを持ちます。[...]usingtypedef

(私のものを強調)

上記は について非常に明確でusingあり、 のルールはtypedef、§8.3/1 の最後を含め、いくつかの段落にまたがっています。

8.3 宣言子の意味 [dcl.meaning]

1 [...] declarator-idに続くオプションのattribute-specifier-seq は、宣言されたエンティティに属します。

(繰り返しますが、私のものを強調してください)


更新: 上記の回答は、正確な意味ではなく、配置する必要がある場所に集中しています。alignasもう少し考えた後でも、上記は有効であるべきだと思います。検討:

7.6.2 アライメント指定子 [dcl.align]

1アライメント指定子は、変数またはクラス データ メンバーに適用できますが、ビット フィールド、関数パラメーター、例外宣言(15.3)、またはregisterストレージ クラスで宣言された変数には適用してはなりません。指定子。アライメント指定子は、クラスの宣言または定義 (それぞれ、詳細型指定子(7.1.6.3) またはクラス ヘッド(第 9 節)) および列挙型の宣言または定義 (それぞれopaque-enum-declarationまたはenum-headで(7.2))。省略記号付きの配置指定子は、パック展開 (14.5.3) です。

明らかに適用できる場合と、明らかに適用できない場合を示しています。上記の質問の例はどちらでもありません。

typedefまたはによって作成された型エイリアスusingは、エイリアス化された型の一部としてアライメント仕様を保持していると主張することもできます。register7.6.2p1 で許可されているように、このエイリアスを使用して変数などを作成できますが、 などで変数を作成することはできません。

その意味で、属性指定子は (7.6.2 の意味で) 延期された方法で適用されるため、アライメント仕様が構文的に正しい場所に配置されている場合でも、OP の例は有効であると思います。

于 2013-04-09T20:48:33.720 に答える
14

に位置合わせを適用することはできませんtypedef。アラインメント指定子の C++ モデルでは、アラインメントは型自体の不可分な部分でありtypedef、新しい型を作成しません (既存の型に新しい名前を提供するだけです)。typedef宣言。

[dcl.align] (7.6.2)p1から:

配置指定子は、変数またはクラス データ メンバーに適用できます [...]。アライメント指定子は、クラスの宣言または定義 (それぞれ、詳細型指定子(7.1.6.3) またはクラス ヘッド(第 9 節)) および列挙型の宣言または定義 (それぞれopaque-enum-declaration またはenum-headで(7.2))。

これらは、標準で配置指定子( alignas(...)) を適用できると規定されている唯一の場所です。これには、宣言もエイリアス宣言も含まれないことに注意してください。typedef

[ dcl.attr.grammar ] (7.6.1)p4 あたり:

エンティティまたはステートメントに関連するattribute-specifier-seqに、そのエンティティまたはステートメントに適用できない属性が含まれている場合、プログラムの形式は正しくありません。

この表現は、 attribute-specifier-seqalignas内に現れる可能性のある属性の他の形式と同様に適用されることを意図していましたが、配置が「実際の」属性から別の種類の属性指定子に切り替わったときに正しく更新されませんでした-seq .

したがって、使用するサンプルコードalignasは形式が正しくないはずです。C++ 標準は現在これを明示的に述べていませんが、使用を許可していないため、代わりに現在未定義の動作が発生します (標準では動作が定義されていないため)。

于 2015-11-30T19:44:27.863 に答える
8

Draft C++11 standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdfはそれについて述べています (Alignment-specifier はalignas( assignment-expression ) の形式です) :

7.6.2 アラインメント指定子 [dcl.align]

1 アライメント指定子は、変数またはクラス データ メンバに適用できますが、ビット フィールド、関数パラメータ、catch 句の仮パラメータ (15.3)、またはで宣言された変数には適用してはなりません。レジスタ ストレージ クラス指定子。アライメント指定子は、クラスまたは列挙型の宣言にも適用できます。省略記号付きの配置指定子はパック展開です。

この元の提案http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdfを見つけました。

アライメント指定子は型の一部にはなりませんが、アライメントされたメンバー変数を持つクラス型を作成することは可能です。

この例では:

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

での使用は違法のようtypedefです。

于 2013-04-03T15:35:00.223 に答える