attributeの指定方法はわかりにくい。attributeを書く事のできる場所というのは、attribute-specifierである。例えば、いまxという名前のint型の変数を宣言、定義する。
int x ;
これに対して、attribute-specifierは、二箇所存在する。
[[]] int x [[]] ;
前者は、simple-declarationのattribute-specifierであり、後者は、noptr-declaratorのattribute-specifierである。
今、xという変数に対して、アライメントを指定したいとする。一体、どちらのattribute-specifierを使えばいいのか。
答え:どちらでもよい。
まず、アライメントを指定するattributeであるalignは、変数に適用しなければならない。つまり、通常は、noptr-declaratorの方に指定する。
int x [[ align(16) ]] ;
では、simple-declarationの方のattribute-specifierは何か。ここに指定したattributeは、宣言の各entityに属すると定義されている。すなわち、
[[ align(16) ]] int x, y, z ;
という宣言は、
int x [[ align(16) ]], y [[ align(16) ]], z [[ align(16) ]] ;
と指定したものと、同じ意味になる。
と、ここまではいい。もっと複雑な例もある。const int 型の変数の宣言には、みっつのattribute-specifierを指定できる。
[[]] const [[/*中央*/]] int x [[]] = 0 ;
中央のattribute-specifierは、type-specifierに属する。これは、型に対してのattributeであって、entityに対するattributeではない。従って、変数というentityに指定するalignは、この中央に位置するattribute-specifierに指定することはできない。
おそらく、一般のユーザーからみると、alignというattributeは、宣言の最初に指定するか、変数名に指定するものだと見るだろう。実際のところ、実用上は、それでいいように思われる。
ところで、変数名に指定するというのが、また分かりにくいのだ。例えば、配列に対してalignを指定するのは、よくある話だと思う。では、その場合、どのように書けばよいのか。
int x [[align(16)]] [256] ; [[align(16)]] int x [256] ;
上の二行は、完全に同じ意味である。どちらの文法を好むかは、人それぞれだと思う。私は、前者の方が明示的だと思うが、後者の方が、初心者には分かりやすいかもしれない。
実は、関数の定義も、二箇所指定できる。
void f [[noreturn]] () { while(true) ; } [[noreturn]] void f() { while(true) ; }
これも、宣言の場合と同等で、先頭のattribute-specifierは、関数に適用したものとみなされる。
上記は、どちらも同じ意味である。これも、どちらを好むかは人それぞれだ。私は前者の方が、明示的で分かりやすいと思うのだが、後者のほうが、初心者受けはいいかもしれない。
ところで、複数書けるところでは、重複することが許されている。noreturnは、ひとつのattribute-specifierの中に、一回だけしか指定できないと定義されている。しかし、それはあくまでひとつattribute-specifierの話である。複数のattribute-specifierでは、それぞれにnoreturnを指定できる。
[[noreturn]] void f [[noreturn]] () { while(true) ; }
この、複数指定しても良いというのは、実は宣言も同じである。
残念ながらクラスには、初心者にも分かりやすいであろう指定方法がない。今、クラスの継承を禁止したいとする。
class [[ final ]] Do_not_derive_me { } ;
これはすこし、初心者には分かりにくいと思うが、残念ながら、こう書くより他に方法はない。
No comments:
Post a Comment