2010-07-19

attributeの分かりにくい指定方法

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: