std.traits
コンパイル時に、 型とシンボルの情報を取り出すためのテンプレートです。 Source:std/traits.d License:
Boost License 1.0. Authors:
Walter Bright, Tomasz Stachowiak (isExpressionTuple), Andrei Alexandrescu Shin Fujishiro
- 関数か、関数ポインタ、デリゲート、
opCallメソッドを持つ構造体、opCallメソッドを持つ構造体へのポインタ、
あるいはopCallメソッドを持つクラス
から返値の型を取得します。
Example:
import std.traits; int foo(); ReturnType!(foo) x; // x は int 型
- 関数か、関数ポインタ、デリゲート、
あるいは opCall メソッドを持つ構造体、構造体へのポインタ、クラスから
引数の型をタプルとして取得します。
Example:
import std.traits; int foo(int, long); void bar(ParameterTypeTuple!(foo)); // void bar(int, long); の宣言 void abc(ParameterTypeTuple!(foo)[1]); // void abc(long); の宣言
- 関数 func の引数の記憶域クラスからなるタプルを返します。
Example:
alias ParameterStorageClass STC; // 略記 void func(ref int ctx, out real result, real param) { } alias ParameterStorageClassTuple!(func) pstc; static assert(pstc.length == 3); // 3引数 static assert(pstc[0] == STC.REF); static assert(pstc[1] == STC.OUT); static assert(pstc[2] == STC.NONE);
- これらのフラグは、 ビットORして複雑な記憶域クラスを表現するのにも使われます。
- 関数 func の属性を返します。
Example:
alias FunctionAttribute FA; // 略記 real func(real x) pure nothrow @safe { return x; } static assert(functionAttributes!(func) & FA.PURE); static assert(functionAttributes!(func) & FA.SAFE); static assert(!(functionAttributes!(func) & FA.TRUSTED)); // @trusted でない
- これらのフラグは、ビットORして複雑な属性を表現するのにも使われます。
- 関数が @safe や @trusted であるかどうかを調べます。
Example:
@system int add(int a, int b) {return a+b;} @safe int sub(int a, int b) {return a-b;} @trusted int mul(int a, int b) {return a*b;} bool a = isSafe!(add); assert(a == false); bool b = isSafe!(sub); assert(b == true); bool c = isSafe!(mul); assert(c == true);
- 全ての関数が @safe か @trusted であるかどうか調べます。
Example:
@system int add(int a, int b) {return a+b;} @safe int sub(int a, int b) {return a-b;} @trusted int mul(int a, int b) {return a*b;} bool a = areAllSafe!(add, sub); assert(a == false); bool b = areAllSafe!(sub, mul); assert(b == true);
- 関数が @system かどうか調べます
Example:
@system int add(int a, int b) {return a+b;} @safe int sub(int a, int b) {return a-b;} @trusted int mul(int a, int b) {return a*b;} bool a = isUnsafe!(add); assert(a == true); bool b = isUnsafe!(sub); assert(b == false); bool c = isUnsafe!(mul); assert(c == false);
- 関数の呼び出し規約を文字列で返します。
Example:
string a = functionLinkage!(writeln!(string, int)); assert(a == "D"); // extern(D) auto fp = &printf; string b = functionLinkage!(fp); assert(b == "C"); // extern(C)
- 関数の可変個引数タイプを判定します。
Example:
void func() {} static assert(variadicFunctionStyle!(func) == Variadic.NO); extern(C) int printf(in char*, ...); static assert(variadicFunctionStyle!(printf) == Variadic.C);
- 可変個引数でない
- C形式の可変個引数
- D形式の、 _argptr と _arguments を使う可変個引数
- 関数は型安全可変個引数
- 呼び出し可能オブジェクト func から関数型を取り出します。
組み込みの typeof をプロパティ関数に使うと、
プロパティ値の型が求まり、これは関数そのものの型ではありません。しかし、
FunctionTypeOf はプロパティ関数の型を求めることができます。
class C { int value() @property; } static assert(is( typeof(C.value) == int )); static assert(is( FunctionTypeOf!(C.value) == function ));
Note:
関数型と関数ポインタ型を混同しないようにご注意ください。 関数型は通常はコンパイル時リフレクションの用途に使われます。 - 構造体かクラスをフィールドのタプルに変換したときの型を取得します。 これは、仮想関数テーブルへのポインタのような隠しフィールドを除いた、 メモリ空間を消費するフィールドのみで構成される タプルとなります。
- 構造体やクラスのフィールドのプリミティブな型のタプルを
topological order で返します。
Example:
struct S1 { int a; float b; } struct S2 { char[] a; union { S1 b; S1 * c; } } alias RepresentationTypeTuple!(S2) R; assert(R.length == 4 && is(R[0] == char[]) && is(R[1] == int) && is(R[2] == float) && is(R[3] == S1*));
- T の表現に以下のいずれかが含まれているときに、true を返します:
- 生のポインタ U* で U がimmutableでないもの
- 配列 U[] で U が immutable でないもの
- クラスやインターフェイス参照 C で C が immutable でないもの
- 連想配列でimmutableでないもの
- delegate
- T の表現が少なくとも以下の1つを含んでいると true
になります:
- 生ポインタ U*
- 配列 U[]
- クラスへの参照型 C
- 連想配列
- delegate
- T の表現が少なくとも以下の1つを含んでいると true
になります:
- 生ポインタ U* で U がimmutableやsharedでないもの
- 配列 U[] で U が immutable や shared でないもの
- クラスへの参照型 C で C が immutable や shared でないもの
- immutable や shared でない連想配列
- shared でない delegate
- S や S の表現に直接埋め込まれた型が単純でないコピーコンストラクタを定義していると true となります。単純でないコピーコンストラクタとは this(this) が構造体に定義されていることを言います。 (構造体以外には単純でないコピーコンストラクタはありません)
- S や S の表現に直接埋め込まれた型が単純でない代入を定義していると true となります。単純でない代入とは 構造体に opAssign(typeof(this)) または opAssign(ref typeof(this)) が定義されていることをいいます。(構造体以外には単純でない代入はありません)
- S か、その表現に直接埋め込まれている型が 単純でないデストラクタを定義していると true となります。単純でないデストラクタとは、 ~this() が構造体に定義されていることを言います。 (構造体以外には、~this() が定義されていても、単純でないデストラクタはありません)
- T が struct か class で name という名前のメンバを持つ時に true となります
- 列挙型 enum E のメンバ一覧を取得します
Parameters:
Returns:E 列挙型。E には値が重複するメンバがあっても構いません。
列挙型 E のメンバからなる静的タプル。 メンバは E で宣言されたのと同じ順番に並びます。 Note:
返される値は厳密に E 型を持ちます。したがって、 以下のコードは明示キャスト無しでは動きません。enum E : int { a, b, c } int[] abc = cast(int[]) [ EnumMembers!E ];
キャストは変数の型を推論するのであれば不要です。 以下の例をどうぞ。 Examples:
enum値の配列を作ります:enum Sqrts : real { one = 1, two = 1.41421, three = 1.73205, } auto sqrts = [ EnumMembers!Sqrts ]; assert(sqrts == [ Sqrts.one, Sqrts.two, Sqrts.three ]);
以下の例の汎用関数 rank(v) は、 列挙型 E からメンバ e を探すのにこのテンプレートを使っています。// e が E の i 番目の列挙子ならば i を返す size_t rank(E)(E e) if (is(E == enum)) { foreach (i, member; EnumMembers!E) { if (e == member) return i; } assert(0, "Not an enum member"); } enum Mode { read = 1, write = 2, map = 4, } assert(rank(Mode.read ) == 0); assert(rank(Mode.write) == 1); assert(rank(Mode.map ) == 2);
- 指定したクラスやインターフェイスの基底型と基底インターフェイスからなる
型タプルを返します。BaseTypeTuple!(Object)
は空の型タプルを返します。
Example:
import std.traits, std.typetuple, std.stdio; interface I { } class A { } class B : A, I { } void main() { alias BaseTypeTuple!(B) TL; writeln(typeid(TL)); // (A,I) を表示 }
- このクラスの全ての基底クラスを、降順の型タプルとして返します。
インターフェイスは含まれません。BaseClassesTuple!(Object) は空の型タプルになります。
Example:
import std.traits, std.typetuple, std.stdio; interface I { } class A { } class B : A, I { } class C : B { } void main() { alias BaseClassesTuple!(C) TL; writeln(typeid(TL)); // (B,A,Object) を表示 }
- このクラスや基底クラスの実装する全てのインターフェイスを並べた
型タプルを返します。複数回implementsされたインターフェイスでも
重複列挙されることはありません。InterfacesTuple!(Object)
は空の型タプルを返します。
Example:
import std.traits, std.typetuple, std.stdio; interface I1 { } interface I2 { } class A : I1, I2 { } class B : A, I1 { } class C : B { } void main() { alias InterfacesTuple!(C) TL; writeln(typeid(TL)); // (I1, I2) を表示 }
- クラス T の全ての基底クラスを降順に並べ、
その後ろにインターフェイスを並べた型タプルを返します。
TransitiveBaseTypeTuple!(Object)
は空の型タプルになります。
Example:
import std.traits, std.typetuple, std.stdio; interface I { } class A { } class B : A, I { } class C : B { } void main() { alias TransitiveBaseTypeTuple!(C) TL; writeln(typeid(TL)); // (B,A,Object,I) を表示 }
- name という名前の、
クラスかインターフェイスである C 型の非静的メンバ関数のタプルを返します。
共変の戻り値型による重複は、もっとも深い派生クラスのものにまとめられます。
Example:
interface I { I foo(); } class B { real foo(real v) { return v; } } class C : B, I { override C foo() { return this; } // I.foo() の共変オーバーライド } alias MemberFunctionsTuple!(C, "foo") foos; static assert(foos.length == 2); static assert(__traits(isSame, foos[0], C.foo)); static assert(__traits(isSame, foos[1], B.foo));
- 指定した型全ての暗黙変換先となれる型を返します。
例えば、さまざまな初期化値から配列を生成する場合などに役に立ちます。
空リストを渡したときや、共通の型が存在しない場合は void
を返します。
Example:
alias CommonType!(int, long, short) X; assert(is(X == long)); alias CommonType!(int, char[], short) Y; assert(is(Y == void));
- T. からの暗黙変換先となりうる型全てのタプルを返します。 Important note: このテンプレートが返す型のリストは、危険な変換を除いているため D 2.005 コンパイラが認めるものより保守的になっています。 例えば ImplicitConversionTargets!(double) には float は含まれません。
- From を To に暗黙変換可能か?
- 型 Rhs の値が
型 Lhs の変数に代入可能なら true となります。
Examples:
static assert(isAssignable!(long, int)); static assert(!isAssignable!(int, long)); static assert(isAssignable!(const(char)[], string)); static assert(!isAssignable!(string, char[]));
- 関数型 F に対して G が covariant であるか、
つまり、F を G 型の関数でオーバーライドできるか、を判定します。
Example:
interface I { I clone(); } interface J { J clone(); } class C : I { override C clone() // I.clone() の共変オーバーライド { return new C; } } // C.clone() は実際に I.clone() をオーバーライドできる static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone))); // C.clone() は J.clone() をオーバーライドできない。 // 返値型 C が J に暗黙変換できないため。 static assert(isCovariantWith!(typeof(C.clone), typeof(J.clone)));
- T が組み込みの整数型かどうかを判定します。bool, char, wchar, dchar は整数型とは見なされません。
- T が組み込みの浮動小数点数型かどうかを判定します。
- T が組み込みの数値型(整数あるいは 浮動小数点数)かどうかを判定します。
- T が組み込みの符号無し数値型かどうかを判定します。
- T が組み込みの符号付き数値型かどうかを判定します。
- T が組み込みの文字列型かどうかを判定します。
- T が組み込みの文字型かどうかを判定します。
- T が組み込みの連想配列型かどうかを判定します。
- Tが静的配列かどうかを判定します。
- 型 T が動的配列型かどうかを判定します。
- 型 T が配列型かどうかを判定します。
- 型 T がポインタ型かどうかを判定します。
- ポインタ型の指す型を返します。
- T が foreach ループを auto 型の1個のループ変数で回せるならば true を返します。 foreach の実装には依存せず、レンジ、 opApply を持つ構造体/クラス、 組み込みの動的配列や静的配列、連想配列でtrueになります。
- タプル T が式タプルかどうか判定します。
- タプル T が型タプルかどうか判定します。
- シンボルまたは型 T が関数ポインタかどうか判定します
- T が delegate かどうか判定します。
- シンボルまたは型 T が関数、関数ポインタ、delegateのどれかであるか判定します。
- T が呼び出し可能オブジェクト、つまり (...) 演算子が使えるか判定します。
- 組み込みtraitsと同じ意味です: __traits(isAbstractFunction, method).
- 型 T についている修飾子があればすべて取り除きます。
Example:
static assert(is(Unqual!(int) == int)); static assert(is(Unqual!(const int) == int)); static assert(is(Unqual!(immutable int) == int)); static assert(is(Unqual!(shared int) == int)); static assert(is(Unqual!(shared(const int)) == int));
- 型 T の値を foreach でループ変数1個でループするときに、 その変数の型は何になるかを返します。これは std.range.ElementType!(Range) とは一致しないことがあります: char/wchar文字列や、 opApplyとレンジインターフェイスを両方実装している場合など。
- 全ての typedef (enum も含む) を型 T から取り除きます。
Example:
enum E : int { a } typedef E F; typedef const F G; static assert(is(OriginalType!G == const int));
- T に対する unsigned 型を返します。 Tが整数型ではないばあい、コンパイルエラーになります。
- 引数のタプルのうち T.sizeof が最大になる型を返します。 複数の型が同じサイズで最大の時は、 最左のものが返されます。
- T に対する signed 型を返します。 Tが整数型ではないばあい、コンパイルエラーになります。
- 数値型Tの負の最小値を返します。
- シンボルまたは型 sth のマングルされた名前文字列を返します。
Example:
mangledName は組み込みの .mangleof プロパティと基本的に同等ですが、 プロパティ関数の正しい名前が手に入ります。module test; import std.traits : mangledName; class C { int value() @property; } pragma(msg, C.value.mangleof); // "i" と表示 pragma(msg, mangledName!(C.value)); // "_D4test1C5valueMFNdZi" と表示
- 真偽値 condition が true なら
T への alias、そうでなければ F への alias となります。
Example:
alias Select!(size_t.sizeof == 4, int, long) Int;
- cond が true ならば b を評価せずに a を返します。逆に false ならば a を評価せずに b を返します。