forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 4
/
attribute.dd
641 lines (521 loc) · 19.5 KB
/
attribute.dd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
Ddoc
$(SPEC_S 属性,
$(GRAMMAR
$(GNAME AttributeSpecifier):
$(GLINK Attribute) $(B :)
$(GLINK Attribute) $(GLINK DeclarationBlock)
$(GNAME Attribute):
$(LINK2 #linkage, $(I LinkageAttribute))
$(LINK2 #align, $(I AlignAttribute))
$(GLINK2 pragma, Pragma)
$(LINK2 #deprecated, $(B deprecated))
$(GLINK ProtectionAttribute)
$(B static)
$(B extern)
$(B final)
$(B synchronized)
$(LINK2 #override, $(B override))
$(LINK2 #abstract, $(B abstract))
$(LINK2 #const, $(B const))
$(LINK2 #auto, $(B auto))
$(LINK2 #scope, $(B scope))
$(V2 $(LINK2 #gshared, $(B __gshared))
$(LINK2 #shared, $(B shared))
$(LINK2 #immutable, $(B immutable))
$(LINK2 #inout, $(B inout))
$(LINK2 #disable, $(B @disable))
)
$(GNAME DeclarationBlock):
$(GLINK2 module, DeclDef)
$(B {) $(GLINK2 module, DeclDefs)$(OPT) $(B })
)
$(P 属性とは、一つ、もしくは複数の宣言を修飾するものです。
一般的な構文は:
)
---
attribute declaration; // かかっている宣言に影響
attribute: // 現在のスコープが終わるまでの
// 全ての宣言に影響
declaration;
declaration;
...
attribute { // ブロック内の全ての宣言に影響
declaration;
declaration;
...
}
---
<h2>$(LNAME2 linkage, リンケージ属性)</h2>
$(GRAMMAR
$(GNAME LinkageAttribute):
$(B extern) $(B $(LPAREN)) $(GLINK LinkageType) $(B $(RPAREN))
$(GNAME LinkageType):
$(B C)
$(B C++)
$(B D)
$(B Windows)
$(B Pascal)
$(B System)
)
$(P C やシステムのAPI関数との互換性は重要ですから、
Dはそれらを簡単に呼び出す手段を提供しています。
$(I LinkageType) は大文字小文字を区別し、
実装によって拡張されることを想定しています ($(B 予約語ではありません))。
$(B C) と $(B D) は必須ですが、
その他は実装によります。
$(B C++) は将来のために予約されています。
$(B System) は Windows 環境では $(B Windows) と同じ意味で、
それ以外の環境では $(B C) と同じ意味になります。
$(B 実装ノート:)
Win32向けのコンパイラは $(B Windows) と $(B Pascal) をサポートすべきです。
)
$(P C
の関数呼び出し規約を指定するには:
)
---------------
extern (C):
int foo(); // foo() は C の呼び出し規約で呼ばれる
---------------
$(P Dの呼び出し規約ならば:)
---------------
extern (D):
---------------
$(P あるいは:)
---------------
extern:
---------------
$(P Windows API の呼び出し規約は:)
---------------
extern (Windows):
void *VirtualAlloc(
void *lpAddress,
uint dwSize,
uint flAllocationType,
uint flProtect
);
---------------
<h2>$(LNAME2 align, アラインメント属性)</h2>
$(GRAMMAR
$(GNAME AlignAttribute):
$(B align)
$(B align) $(B $(LPAREN)) $(GLINK2 lex, IntegerLiteral) $(B $(RPAREN))
)
$(V1
$(P 構造体メンバのアラインメントを指定します。 $(B align) と単独で書くと、
その環境のCコンパイラでのデフォルト値へ設定されます。
$(I Integer)
を指定すると、
そのバイト境界へとメンバを整列します。
)
$(P 協調するCコンパイラと挙動を揃えるために、align
属性はしばしば不思議な動作をします。例えばDigital Mars C++の場合こうなります:
)
---------------
struct S {
align(4) byte a; // オフセット 0 に配置
align(4) byte b; // オフセット に配置
}
---------------
$(P $(I AlignAttribute) は、CのABIとの互換のために用意されており、
プラットフォーム間のバイナリ互換性のために用意されているものではありません。
そちらの目的には、構造体に明示的に詰め物を入れます:
)
---------------
align (1) struct S {
byte a; // オフセット 0 に配置
byte[3] filler1;
byte b; // オフセット 4 に配置
byte[3] filler2;
}
---------------
$(P 1を指定すると整列は行われず、
全てのメンバがきっちり詰め込まれます。
)
$(P
$(I NewExpression) で割り付けたメモリへの参照やポインタは、
$(D size_t) の倍数以外のバイト境界に揃えるのは避けてください。
ガベージコレクタは、GCの割り当てたオブジェクトへの参照やポインタは $(D size_t)
バイト境界に存在すると仮定して動作しています。
そうなっていない場合、動作は未定義です。
)
$(P $(I AlignAttribute) は、構造体や構造体メンバ以外に宣言された場合には、
無視されます。
クラスのメンバに適用されるかどうかは実装依存です。
)
$(P $(I AlignAttribute) は、struct、union、class、
あるいは関数スコープに入るときにデフォルトに戻され、
スコープを抜けると元に戻ります。
基底クラスからアラインメントが継承されることもありません。
)
)
$(V2
$(P 以下のアラインメントの設定に用います:)
$(OL
$(LI 変数)
$(LI 構造体フィールド)
$(LI 共用体フィールド)
$(LI クラスフィールド)
$(LI 構造体型、共用体型、クラス型)
)
$(P $(B align) と単独で書くと、
アライメントをデフォルトに戻します。
つまり、その環境のCコンパイラでのデフォルト値へ設定されます。)
--------
struct S {
align:
byte a; // オフセット 0 に配置
int b; // オフセット 4 に配置
long c; // オフセット 8 に配置
}
auto sz = S.sizeof; // 16
--------
$(P $(I IntegerLiteral)
を指定した時は、その非デフォルト値を指定されたときの環境の C
コンパイラの挙動と同じ動作をします。2 の冪乗を指定する必要があります。
)
$(P 1を指定すると整列は行われず、
全てのメンバがきっちり詰め込まれます。
)
--------
struct S {
align (1):
byte a; // オフセット 0 に配置
int b; // オフセット 1 に配置
long c; // オフセット 5 に配置
}
auto sz = S.sizeof; // 16
--------
$(P フィールドへのアラインメント設定は、
そのフィールドを持つ構造体やクラス自身のアラインメントには影響しません。
それらは、その外側で設定されたアラインメントに影響されます。)
--------
align (2) struct S {
align (1):
byte a; // オフセット 0 に配置
int b; // オフセット 1 に配置
long c; // オフセット 5 に配置
}
auto sz = S.sizeof; // 14
--------
$(P フィールドのアラインメントを指定すると、フィールド自身のサイズに関係なく、
その 2 の冪にオフセットが揃うようになります。)
--------
struct S {
align (4):
byte a; // オフセット 0 に配置
byte b; // オフセット 4 に配置
short c; // オフセット 8 に配置
}
auto sz = S.sizeof; // 12
--------
$(P
$(I NewExpression) で割り付けたメモリへの参照やポインタは、
$(D size_t) の倍数以外のバイト境界に揃えるのは避けてください。
ガベージコレクタは、GCの割り当てたオブジェクトへの参照やポインタは $(D size_t)
バイト境界に存在すると仮定して動作しています。
そうなっていない場合、動作は未定義です。
)
$(P $(I AlignAttribute) は、struct、union、class、
あるいは関数スコープに入るときにデフォルトに戻され、
スコープを抜けると元に戻ります。
基底クラスからアラインメントが継承されることもありません。
)
)
<h2>$(LNAME2 deprecated, deprecated 属性)</h2>
$(P ライブラリには、
後方互換性のために非推奨の機能を残す必要が
しばしば生じます。このような機能の制限には 'deprecated'
と印をつけておきます。すると、
コンパイラスイッチの設定によって、
非推奨の機能を使うコードをエラーにすることが可能になります:
)
---------------
deprecated
{
void oldFoo();
}
---------------
$(P $(B 実装ノート:)
コンパイラは、
非推奨機能のコンパイルの際に警告するかしないかを指定するスイッチを用意しておくべきです。
)
<h2>アクセス保護属性</h2>
$(GRAMMAR
$(GNAME ProtectionAttribute):
$(B private)
$(B package)
$(B protected)
$(B public)
$(B export)
)
$(P アクセス保護属性は、
$(B private), $(B package), $(B protected),
$(B public), $(B export), のいずれか一つです。
)
$(P private は、同じクラスのメンバのみが参照できる、
あるいは同じモジュールのクラス/関数のみが参照できることを示します。
private メンバをオーバーライドすることはできません。
モジュールのメンバを private と宣言するのは、
Cでの $(B static)
宣言と同等です。
)
$(P package は、モジュールは違っても同じパッケージに属するコードからの
アクセスは許可するようにprivateを拡張したものです。
これは、モジュールがネストしたパッケージの中にある場合は、
最も内側のパッケージについてのみ適用されます。
)
$(P protected は、同じクラスかその派生クラスのメンバ、
または同じモジュールに属するコード
からのみからのみ参照できることを示します。
派生クラスのメンバ関数から
protected なインスタンスメンバへアクセスする場合、
そのメンバ関数の 'this'
オブジェクトに属するメンバについてのみ、アクセスが可能です。
モジュールのメンバを protected
とするコードは不正です。
)
$(P public は、同じ実行ファイル中の全てのコードからアクセス可能なことを示します。
)
$(P export は、実行ファイルの外からもアクセスできることを示します。
DLLから関数定義をエクスポートする、
というのと似ています。
)
$(P 保護属性は名前の探索の際には考慮されません。
具体的には、同名の2つのシンボルがスコープ内にあって、
どちらも修飾がされずに使われていれば、
保護属性によるとどちらかがアクセス不可能な場合であっても、曖昧でエラーとなります。
例:
)
---------------
module A;
private class Foo {}
---------------
---------------
module B;
public class Foo {}
---------------
---------------
import A;
import B;
Foo f1; // エラー、A.Foo または B.Foo
B.Foo f2; // ok
---------------
<h2>$(LNAME2 const, const 属性)</h2>
$(P $(B const) は、コンパイル時に評価できる定数につける属性です。
例えば:
)
---------------
const int foo = 7;
const {
double bar = foo + 6;
}
---------------
$(V1
$(P 初期化子なしのconst宣言は
コンストラクタ (クラスフィールドの場合) または静的コンストラクタ
(staticメンバやモジュール変数の場合) で初期化する必要があります。
)
---------------
const int x;
const int y;
static this()
{
x = 3; // ok
// エラー: y が未初期化
}
void foo()
{
x = 4; // エラー、x は const でここは静的コンストラクタの中ではない
}
class C
{
const int a;
const int b;
static const int c;
static const int d;
this() {
a = 3; // ok
a = 4; // ok。複数回の初期化は可能
C p = this;
p.a = 4; // エラー。this のメンバだけを初期化可能
c = 5; // エラー。静的コンストラクタで初期化すべき
// エラー。b が未初期化。
}
this(int x) {
this(); // ok。転送コンストラクタ
}
static this() {
c = 3; // ok
// エラー。d が未初期化。
}
}
---------------
$(P 初期化子もコンストラクタもないconstモジュール変数の宣言は、
エラーにはなりません。これは、
宣言のためのみに使ってリンクはしないで、
実装はリンクされる他のモジュールに書く、という技法をサポートするためです。
)
)
$(V2
<h2>$(LNAME2 immutable, immutable 属性)</h2>
<h2>$(LNAME2 gshared, __gshared 属性)</h2>
$(P デフォルトでは、immutable はでないグローバル宣言はスレッドローカル記憶域に配置されます。
ただし、$(B __gshared)
属性が付いているときは全スレッド間で共有されるようになります。)
---
int foo; // それぞれのスレッド毎に独自の変数領域 foo を持つ。
__gshared int bar; // bar は全スレッドで共有される。
---
$(P $(B __gshared) はメンバ変数やローカル変数にも適用可能です。
これらの場合は $(B __gshared) は $(B static) と基本的には同じ意味になり、
ただし、
スレッドローカルではなく全スレッドで共有される変数となります。)
---
class Foo {
__gshared int bar;
}
int foo() {
__gshared int bar = 0;
return bar++; // スレッドセーフでない
}
---
$(P $(B shared) と違い、$(B __gshared)
スレッド間競合や動機の問題に関する安全を何も提供しません。
$(B __gshared) とマークされた変数に正しく同期アクセスするのは、
プログラマの責任です。)
$(P $(B __gshared) はセーフモードでは使用できません。)
<h2>$(LNAME2 shared, shared 属性)</h2>
<h2>$(LNAME2 inout, inout 属性)</h2>
<h2>$(LNAME2 disable, @disable 属性)</h2>
$(P $(CODE @disable) とマークされた宣言への参照は、
コンパイルエラーとなります。
これによって、ある種の操作やオーバーロードを、
実行時エラーにするのではなくコンパイルエラーにできます。
)
---
struct T {
@disable this(this) { } // この関数をdisableすることでTがコピー不可能となる
}
struct S {
T t; // コピー不可能メンバがあるとS全体もコピー不可能
}
@disable void foo() { }
void main() {
S s;
S t = s; // エラー、S はコピー不可能
foo(); // エラー、fooはdiableされている
}
---
)
<h2>$(LNAME2 override, override 属性)</h2>
$(P $(B override) は、仮想関数に適用する属性です。
これは、
そのメンバ関数は基底クラスの同名同引数の関数をオーバーライドしているのだ、
という宣言になります。override属性は、基底クラスの仮想関数の引数を変更して、
全ての派生クラスの実装を変更しなくてはならない、
という状況などに便利です。
)
---------------
class Foo {
int bar();
int abc(int x);
}
class Foo2 : Foo {
override {
int bar(char c); // エラー。 Foo には bar(char) という関数はない
int abc(int x); // ok
}
}
---------------
<h2>static 属性</h2>
$(P $(B static) 属性は関数もしくはデータに適用されます。
これは、その宣言が特定のインスタンスに関するものではなく、
ある型に関するものである、という意味になります。
言い方を変えると、$(B this) を参照しない、ということです。
$(B static) がその他の宣言についた場合は無視されます。
)
---------------
class Foo {
static int bar() { return 6; }
int foobar() { return 7; }
}
...
Foo f = new Foo;
Foo.bar(); // 6を返す
Foo.foobar(); // エラー。Fooのインスタンスが無い。
f.bar(); // 6を返す
f.foobar(); // 7を返す
---------------
$(P
仮想関数はstaticにはできません。
)
$(P
staticデータは、インスタンス毎に一個ずつではなく、
プログラム中に唯一つ保持されます。
)
$(P
Dのstatic属性は、Cのような"ファイルローカル"という別の意味は持ちません。
この用途には、$(B private) 属性が使用されます。
例えば:
)
---------------
module foo;
int x = 3; // x はグローバル
private int y = 4; // y はモジュールfoo内ローカル
---------------
<h2>$(LNAME2 auto, auto 属性)</h2>
$(P $(B auto) 属性は、他の属性がなく、
型推論を行いたいときに使用します。
)
---
auto i = 6.8; // i を double 型として宣言
---
<h2>$(LNAME2 scope, scope 属性)</h2>
$(P
$(B scope) 属性は、ローカル変数とクラスの宣言に使用できます。
クラス宣言では、 $(B scope) 属性をつけたクラスは、
$(I scope クラス) となります。
ローカル変数宣言の $(B scope) 属性は、RAII (Resource Acquisition
is Initialization) を実装するために活用できます。
すなわち、変数がスコープを外れると、オブジェクトのデストラクタが
自動的に呼び出されます。例え例外によってスコープから出るときであっても、
やはりデストラクタが呼ばれます。要するに、$(B scope) によって、
何らかの後処理を確実に実行することが保証できます。
)
$(P
二つ以上の $(B scope) 変数が同じ箇所でスコープを抜ける場合、
デストラクタは、
変数が構築されたのと逆順で実行されます。
)
$(P
$(B scope) は、グローバルデータや静的データ、関数の ref/out
パラメータには適用できません。$(B scope) の配列、関数からの $(B scope)
返値も禁止されています。 $(B scope)
への初期化以外の代入も禁じられています。
$(B Rationale:) これらの制限は、
もっともな理由が見つかれば将来的には緩和されるかもしれません。
)
<h2>$(LNAME2 abstract, abstract 属性)</h2>
$(P
abstractなクラスは、直接インスタンス化することができません。
他の、abstract
でないクラスの基底クラスとしてのみインスタンス化できます。
)
$(P
クラスは、abstract属性付きで宣言された時か、
abstractと宣言された仮想メンバ関数を持っているときに
abstractになります。
)
$(P
非仮想関数をabstractと宣言することはできません。
)
$(P
abstract と宣言された関数であっても、関数定義本体を書くことができます。
これは、必ずオーバーライドされる必要があるにせよ、
$(SINGLEQUOTE クラスの基本共通機能) を提供できるようにするためです。
)
)
Macros:
TITLE=属性
WIKI=Attribute
CATEGORY_SPEC=$0