Improve this page Github へのログインが必要です。 簡単な修正は、ここから fork、オンライン編集、pull request ができます。 大きな修正については、 通常の clone で行って下さい。 Page wiki 関連するWikiページを参照・編集 English このページの英語版(原文)

特性

特性 (trait) は、コンパイル時に、 プログラムからコンパイラの内部情報を取得できるようにする言語拡張です。 コンパイル時リフレクション と呼ばれることもあります。 構文は(pragmaに似た)簡単に拡張可能な形式で、 新しい機能が必要になったら すぐに追加できるようになっています。

TraitsExpression:
    __traits ( TraitsKeyword , TraitsArguments )

TraitsKeyword:
    isAbstractClass
    isArithmetic
    isAssociativeArray
    isFinalClass
    isFloating
    isIntegral
    isScalar
    isStaticArray
    isUnsigned
    isVirtualFunction
    isVirtualMethod
    isAbstractFunction
    isFinalFunction
    isStaticFunction
    isRef
    isOut
    isLazy
    hasMember
    identifier
    parameterNames
    getMember
    getOverloads
    getVirtualFunctions
    getVirtualMethods
    parent
    classInstanceSize
    allMembers
    derivedMembers
    isSame
    compiles

TraitsArguments:
    TraitsArgument
    TraitsArgument , TraitsArguments

TraitsArgument:
    AssignExpression
    Type

isArithmetic

引数が全て、算術型であるか算術型の式である場合、 true を返します。 それ以外の場合は false を返します。 引数が無い場合は false を返します。

import std.stdio;

void main() {
  int i;
  writeln(__traits(isArithmetic, int));
  writeln(__traits(isArithmetic, i, i+1, int));
  writeln(__traits(isArithmetic));
  writeln(__traits(isArithmetic, int*));
}

出力:

true
true
false
false

isFloating

isArithmetic と同じように、浮動小数点数型 (虚数型と複素数型を含む) かどうかを判定します。

isIntegral

isArithmetic と同じように、整数型 (文字型を含む) かどうかを判定します。

isScalar

isArithmetic と同じように、スカラ型 かどうかを判定します。

isUnsigned

isArithmetic と同じように、符号無し型 かどうかを判定します。

isStaticArray

isArithmetic と同じように、静的配列型 かどうかを判定します。

isAssociativeArray

isArithmetic と同じように、連想配列型 かどうかを判定します。

isAbstractClass

引数が全て、abstractクラス型であるかabstractクラス型の式である場合、 true を返します。 それ以外の場合は false を返します。 引数が無い場合は false を返します。

import std.stdio;

abstract class C { int foo(); }

void main() {
  C c;
  writeln(__traits(isAbstractClass, C));
  writeln(__traits(isAbstractClass, c, C));
  writeln(__traits(isAbstractClass));
  writeln(__traits(isAbstractClass, int*));
}

出力:

true
true
false
false

isFinalClass

isAbstractClass と同じように、finalクラス かどうかを判定します。

isVirtualFunction

isVirtualMethod と同様ですが、 他の関数のオーバーライドでない final 関数に対しては true を返します。

isVirtualMethod

引数を1つ取ります。その引数が仮想関数なら true、そうでなければ false を返します。 他の関数のオーバーライドでない final 関数に対しては false を返します。

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

void main() {
  writeln(__traits(isVirtualMethod, C.bar));  // true
  writeln(__traits(isVirtualMethod, S.bar));  // false
}

isAbstractFunction

引数を1つ取ります。その引数がabstract関数なら true、そうでなければ false を返します。

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

class AC {
  abstract void foo();
}

void main() {
  writeln(__traits(isAbstractFunction, C.bar));   // false
  writeln(__traits(isAbstractFunction, S.bar));   // false
  writeln(__traits(isAbstractFunction, AC.foo));  // true
}

isFinalFunction

引数を1つ取ります。その引数がfinal関数なら true、そうでなければ false を返します。

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
  final void foo();
}

final class FC {
  void foo();
}

void main() {
  writeln(__traits(isFinalFunction, C.bar));	  // false
  writeln(__traits(isFinalFunction, S.bar));	  // false
  writeln(__traits(isFinalFunction, C.foo));	  // true
  writeln(__traits(isFinalFunction, FC.foo));  // true
}

isStaticFunction

引数を一つ取り、それが静的関数ならば、 つまり context pointer を持たないならば true、そうでなければ false を返します。

isRef, isOut, isLazy

引数を1つとります。引数が宣言であった場合、 それぞれ ref, out, lazy ならば true を返し、それ以外では false になります。

void fooref(ref int x) {
  static assert(__traits(isRef, x));
  static assert(!__traits(isOut, x));
  static assert(!__traits(isLazy, x));
}

void fooout(out int x) {
  static assert(!__traits(isRef, x));
  static assert(__traits(isOut, x));
  static assert(!__traits(isLazy, x));
}

void foolazy(lazy int x) {
  static assert(!__traits(isRef, x));
  static assert(!__traits(isOut, x));
  static assert(__traits(isLazy, x));
}

hasMember

第一引数には、メンバがあるか調べたい型か、 メンバがあるか調べたい型を持つ式を指定します。 第二引数は文字列です。 その文字列が指定された型の有効なプロパティだった場合 true、そうでなければ false を返します。

import std.stdio;

struct S {
  int m;
}

void main() {
  S s;

  writeln(__traits(hasMember, S, "m")); // true
  writeln(__traits(hasMember, s, "m")); // true
  writeln(__traits(hasMember, S, "y")); // false
  writeln(__traits(hasMember, int, "sizeof")); // true
}

identifier

シンボルを1つ引数としてとり、 そのシンボルの識別子を文字列として返します。

parameterNames

引数を一つ、関数を受け取ります。 関数の仮引数名を文字列リテラルとして格納した配列を返します。

import std.stdio;

void foo(int x, int y) {}

void main() {
  foreach (i; __traits(parameterNames, foo)) {
    writeln(i);
  }
}

以下のように表示されます:

x
y

getMember

二つ引数を取り、 第二引数は文字列です。 "第一引数 . 第二引数を識別子化したもの" という形の式を返します。

import std.stdio;

struct S {
  int mx;
  static int my;
}

void main() {
  S s;

  __traits(getMember, s, "mx") = 1;  // s.mx=1; と同じ
  writeln(__traits(getMember, s, "m" ~ "x")); // 1

  __traits(getMember, S, "mx") = 1;  // エラー、S.mx のための this がない
  __traits(getMember, S, "my") = 2;  // ok
}

getOverloads

第一引数にはクラス型か、 クラス型を持つ式を指定します。 第二引数には、 そのクラスの関数名にマッチする文字列を指定します。 結果は、その名前で定義されている関数全ての配列です。

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getOverloads, D, "foo"))
    writeln(typeid(typeof(t)));

  alias typeof(__traits(getOverloads, D, "foo")) b;
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getOverloads, d, "foo")[1](1);
  writeln(i);
}

出力:

void()
int()
void()
int()
2

getVirtualFunctions

getVirtualMethods と同様ですが、 他の関数のオーバーライドでない final 関数も含まれます。

getVirtualMethods

第一引数にはクラス型か、 クラス型を持つ式を指定します。 第二引数には、 そのクラスの関数名にマッチする文字列を指定します。 結果は、その名前で定義されている仮想関数全ての配列です。 他の関数のオーバーライドでない final 関数が含まれません。

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getVirtualMethods, D, "foo"))
    writeln(typeid(typeof(t)));

  alias typeof(__traits(getVirtualMethods, D, "foo")) b;
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getVirtualMethods, d, "foo")[1](1);
  writeln(i);
}

出力:

void()
int()
void()
int()
2

parent

シンボル一つに評価される引数を一つとり、 その親シンボルを返します。

classInstanceSize

クラス型かクラス型を持つ式一つを 引数に取ります。 返値は size_t 型で、 値はそのクラスのインスタンスが消費するバイト数になります。 この値は、クラスの静的型に基づいたサイズです。 多態は考慮されません。

allMembers

型か、 型を持つ式一つを引数にとります。 返値は文字列リテラルのタプルで、 指定された型及びその基底クラスの全てのメンバの 名前が格納されています。 名前が重複することはありません。 また、組み込みのプロパティは含まれません。

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto b = [ __traits(allMembers, D) ];
  writeln(b);
  // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]
}

結果の文字列配列がどのような順番になっているかは 特に定義されていません。

derivedMembers

型か、 型を持つ式一つを引数にとります。 返値は文字列リテラルのタプルで、 指定された型の全てのメンバの名前が格納されています。 名前が重複することはありません。 基底クラスのメンバは含まれません。 また、組み込みのプロパティは含まれません。

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto a = [__traits(derivedMembers, D)];
  writeln(a);    // ["__ctor", "__dtor", "foo"]
}

結果の文字列配列がどのような順番になっているかは 特に定義されていません。

isSame

二つの引数を受け取り、同じシンボルならば true、 そうでなければ false を返します。

import std.stdio;

struct S { }

int foo();
int bar();

void main() {
  writeln(__traits(isSame, foo, foo)); // true
  writeln(__traits(isSame, foo, bar)); // false
  writeln(__traits(isSame, foo, S));   // false
  writeln(__traits(isSame, S, S));     // true
  writeln(__traits(isSame, std, S));   // false
  writeln(__traits(isSame, std, std)); // true
}

二つの引数がリテラルとenumで構成された式であって、 同じ値に評価されれば、true が返ります。

compiles

全ての引数がコンパイルが通る(意味的に正しい) ならば、 true を返します。 引数としては、 文法的に正しいシンボル,型,式のいずれかを指定できます。 文や宣言を引数として指定することはできません。

ゼロ引数で呼び出した場合 false となります。

import std.stdio;

struct S {
  static int s1;
  int s2;
}

int foo();
int bar();

void main() {
  writeln(__traits(compiles));                      // false
  writeln(__traits(compiles, foo));                 // true
  writeln(__traits(compiles, foo + 1));             // true
  writeln(__traits(compiles, &foo + 1));            // false
  writeln(__traits(compiles, typeof(1)));           // true
  writeln(__traits(compiles, S.s1));                // true
  writeln(__traits(compiles, S.s3));                // false
  writeln(__traits(compiles, 1,2,3,int,long,std));  // true
  writeln(__traits(compiles, 3[1]));                // false
  writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false
}

使い方としては、例えばこんなものがあります: