web-dev-qa-db-ja.com

C ++ 11のalignas()はどこで使用できますか?

コードを標準化して移植性を高めるために、私は

_#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()を配置できる場所と配置できない場所が不思議です。

EDIT(Apr 2013)

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

配置指定子は、変数またはクラスデータメンバーに適用できますが、ビットフィールド、関数パラメーター、catch句の仮パラメーター(15.3)、または記憶域クラス指定子を登録します。 alignment-specifierは、クラスまたは列挙型の宣言にも適用できます。省略記号付きの配置指定子は、パック拡張(14.5.3)です。

すでにRed XIIIによって掘り起こされたように。しかし、私はこれが上記の私のテストにとって何を意味するのかを知るほど専門家ではありません。

Clangが私の属性を受け入れるという事実が何らかの意味を持っている場合、usingの代わりにtypedefディレクティブを使用しようとすると、clangも不平を言うことにおそらく言及する価値があります。また、この質問の以前のバージョンのステートメントとは異なり、gccは警告を表示するだけでなく、実際に私の調整の希望を無視します。

33
Walter

typedefに配置を適用することはできません。配置指定子のC++モデルでは、配置は型自体の不可分の一部であり、typedefは新しい型を作成しない(既存の型に新しい名前を提供するだけである)ため、意味がないtypedef宣言で位置揃え指定子を適用します。

から[dcl.align](7.6.2)p1

alignment-specifierは、変数またはクラスデータメンバー[...]に適用できます。 alignment-specifierは、クラスの宣言または定義にも適用できます(elaborated-type-specifier(7.1 .6.3)またはclass-head(条項9)、それぞれ)および列挙の宣言または定義(opaque-enum-declaration内) またはenum-head、それぞれ(7.2))。

これらは、標準でalignment-specifieralignas(...))が適用される可能性があると記載されている唯一の場所です。このしないtypedef宣言もalias-declarationsも含むことに注意してください。

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

エンティティまたはステートメントに付随するattribute-specifier-seqに、そのエンティティへの適用が許可されていないattributeが含まれている場合またはステートメント、プログラムの形式が正しくありません。

この表現は、alignasおよびattribute-specifier-seq内に出現する可能性のある他の形式の属性に適用することを意図していたが、次の場合に正しく更新されなかった「実際の」属性から別の種類の属性指定子シーケンスに切り替えられた配置。

したがって、alignasを使用したコード例は、であると想定されています。現在、C++標準はこれを明示的に述べていませんが、使用を許可していません。そのため、代わりに現在未定義の動作が発生します(標準では動作が定義されていないため)。

11
Richard Smith

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]

2typedef-nameは、alias-declarationによっても導入できます。 usingキーワードに続くidentifierは、typedef-nameおよびoptionalattribute-specifier-seqの後にidentifierが続きますtypedef-name 。これは、typedef指定子によって導入された場合と同じセマンティクスを持っています。 [...]

(強調鉱山)

上記はusingについては非常に明確です。typedefの規則は、§8.3/ 1の最後を含むいくつかの段落に広がっています。

8.3宣言子の意味[意味を除く]

1 [...]オプションのattribute-specifier-seqfollowing adeclarator-id appertains to宣言されたエンティティ。

(再び、強調鉱山)


更新:上記の回答はwhereに集中しています。正確な意味ではなく、alignasを配置する必要があります。もう少し考えてみても、上記は妥当だと思います。考慮してください:

7.6.2配置指定子[dcl.align]

1alignment-specifierは変数またはクラスデータメンバーに適用できますが、ビットフィールド、関数パラメーター、exception-declaration(15.3)、またはregisterストレージクラス指定子で宣言された変数。 alignment-specifierは、クラスの宣言または定義にも適用できます(elaborated-type-specifier(7.1 .6.3)またはclass-head(条項9)、それぞれ)および列挙の宣言または定義(opaque-enum-declaration内) またはenum-head、それぞれ(7.2))。省略記号付きのalignment-specifierは、パック展開(14.5.3)です。

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

typedefまたはusingによって作成された型のエイリアスが、エイリアスされた型の一部として配置仕様を運ぶと主張することもできます。このエイリアスは、7.6.2p1で許可されている変数などを作成するために使用できますが、registerなどを使用して変数を作成するためには使用できません。

その意味では、属性指定子は(7.6.2の意味で)据え置きの方法で適用されるので、配置仕様が構文的に正しい場所に配置されている場合、OPの例は引き続き有効であると思います。

27
Daniel Frey

C++ 11標準の草案 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf はそれについて述べています(Alignment-Specifier is of theフォームalignas(割り当て式)):

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

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

私はこの最初の提案を見つけました http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf 、それは言う:

Alignment-specifierは型の一部にはなりませんが、整列されたメンバー変数でクラス型を作成することは可能です。

この例では:

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

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

7
iefserge