D 2.0
About Japanese Translation

Last update Sun Dec 19 23:27:30 2010

std.variant

このモジュールは discriminated union 型( タグ付きunion, 代数的データ型 としても知られている)を実装しています。このような型は、 任意の型を受け取るバイナリインターフェイスや、スクリプト言語とのインターフェイス、 プロトタイピング中などに有用です。

Synopsis:
 Variant a; // 使用前には代入すること。そうでないと例外
 // 整数で初期化; int型になる
 Variant b = 42;
 assert(b.type == typeid(int));
 // 値を読む
 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
 // 言語の規則に基づく自動変換
 auto x = b.get!(real);
 // variantを含む他の型をなんでも代入できる
 a = b;
 a = 3.14;
 assert(a.type == typeid(double));
 // 暗黙変換は組み込み型と同様に動作
 assert(a > b);
 // 変換可能性のチェック
 assert(!a.convertsTo!(int)); // double は int に変換できない
 // 文字列とその他配列型のサポート
 a = "now I'm a string";
 assert(a == "now I'm a string");
 a = new int[42]; // 配列も代入可能
 assert(a.length == 42);
 a[5] = 7;
 assert(a[5] == 7);
 // クラスの値も代入可能
 class Foo {}
 auto foo = new Foo;
 a = foo;
 assert(*a.peek!(Foo) == foo); // 完全な型情報を保持

Source:
std/variant.d

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Credits:
Brad Roberts によりレビューされました。また Daniel Keep によるコードレビューで以下の改善が進みました: (1)配列サポートの改善 (2)連想配列のサポート (3)GCに優しい実装。

struct VariantN(size_t maxDataSize,AllowedTypesX...);
VariantN は実装詳細の一部で、ユーザーコードで使われるのは非常にまれです。 VariantN を裏で使用する型は2つあります:

  1. Algebraic: 限定された型のみを格納する discriminated union (例えば Algebraic!(int, double, string) はこの3つの型のみを格納でき、その他の値は全て拒否します。 )
  2. Variant: 特に型を限定しない discriminated union です。 制限としては、格納できる最大の型は、 最大の組み込み型のサイズ以下でなければいけません。 これはつまり、Variant には全てのプリミティブ型と 大きな struct 以外の任意のユーザー定義型を入れられるということになります


AlgebraicVariant のどちらも VariantN のインターフェイスを提供しています。(個別のドキュメントは下参照)

VariantN は、格納できる最大の型のサイズ (maxDataSize)と、格納可能な型のリスト (AllowedTypesX)をパラメタにとる discriminated union 型です。 リストが空だった場合、maxDataSize(を境界整列のため切り上げた値)以下のサイズの型ならなんでも VariantN オブジェクトに格納できるようになります。



template allowed(T)
コンパイル時に、TAllowedTypesX を比べて TVariantN 格納できるかどうか判定します。 AllowedTypesX が空ならば、maxSize 以下のサイズを持つ全ての型が格納可能です。

template opCall(T)
引数から VariantN のオブジェクトを構築します。 格納不可能な型の場合、コンパイル時にエラーになります。

template opAssign(T)
VariantN に値を代入します。 格納不可能な型の場合、コンパイル時にエラーになります。

VariantN opAssign(T rhs);
VariantN に値を代入します。 格納不可能な型の場合、コンパイル時にエラーになります。

const bool hasValue();
VariantN に有効な値が (初期化もしくは代入で) 格納されてるときに true になります。

Example:
 Variant a;
 assert(!a.hasValue);
 Variant b;
 a = b;
 assert(!a.hasValue); // まだなにも格納されていない
 a = 5;
 assert(a.hasValue);


template peek(T)
VariantNぴったり T 型の値が格納されていたら、その値へのポインタを返します。 そうでなければ null を返します。 T がそもそも格納不可能な型の場合、peek がコンパイルエラーになります。

Example:
 Variant a = 5;
 auto b = a.peek!(int);
 assert(b !is null);
 *b = 6;
 assert(a == 6);


T* peek();
VariantNぴったり T 型の値が格納されていたら、その値へのポインタを返します。 そうでなければ null を返します。 T がそもそも格納不可能な型の場合、peek がコンパイルエラーになります。

Example:
 Variant a = 5;
 auto b = a.peek!(int);
 assert(b !is null);
 *b = 6;
 assert(a == 6);


const TypeInfo type();
現在格納されている値の typeid を返します。

template convertsTo(T)
VariantN に格納されているオブジェクトが型 U に暗黙変換可能なときに true を返します。変換可能性のチェックは ImplicitConversionTargets で行われます。

bool convertsTo();
VariantN に格納されているオブジェクトが型 U に暗黙変換可能なときに true を返します。変換可能性のチェックは ImplicitConversionTargets で行われます。

template get(T) if (!is(T == const))
VariantN オブジェクトに格納された値を、 指定された型 T (正確には DecayStaticToDynamicArray!(T)) に暗黙変換して返します。 暗黙変換が不可能な場合、VariantException 例外を投げます。

T get();
VariantN オブジェクトに格納された値を、 指定された型 T (正確には DecayStaticToDynamicArray!(T)) に暗黙変換して返します。 暗黙変換が不可能な場合、VariantException 例外を投げます。

template coerce(T)
VariantN に格納された値を指定の型 T に明示的に変換 (coerce) して返します。 T が文字列の場合は、値は文字列に整形されます。 VariantN に文字列が格納されている場合は、 文字列を T 型の値としてparseして返します 変換が失敗した場合、VariantException 例外を投げます。

T coerce();
VariantN に格納された値を指定の型 T に明示的に変換 (coerce) して返します。 T が文字列の場合は、値は文字列に整形されます。 VariantN に文字列が格納されている場合は、 文字列を T 型の値としてparseして返します 変換が失敗した場合、VariantException 例外を投げます。

string toString();
格納された値を文字列化して返します。

template opEquals(T)
"==" と "!=" 演算子で使われる等値性判定です。

bool opEquals(T rhs);
"==" と "!=" 演算子で使われる等値性判定です。

template opCmp(T)
"<", "<=", ">", ">=" 演算子で使われる比較処理です。 格納された値と rhs の間で意味のある比較ができない場合、 例外を投げます。

int opCmp(T rhs);
"<", "<=", ">", ">=" 演算子で使われる比較処理です。 格納された値と rhs の間で意味のある比較ができない場合、 例外を投げます。

hash_t toHash();
格納された値のハッシュ値を計算します。

template opAdd(T)
template opSub(T)
VariantN オブジェクトと数値型の間の算術演算です。 計算結果は、 演算対象の二つの型から決まる型を格納した VariantN オブジェクトで返されます。 型変換はDの組み込みの算術演算と同じ規則で決まります。

VariantN opAdd(T rhs);
VariantN オブジェクトと数値型の間の算術演算です。 計算結果は、 演算対象の二つの型から決まる型を格納した VariantN オブジェクトで返されます。 型変換はDの組み込みの算術演算と同じ規則で決まります。

template opMul(T)
template opDiv(T)
template opMod(T)
template opAnd(T)
template opOr(T)
template opXor(T)
template opShl(T)
template opShr(T)
template opUShr(T)
template opCat(T)
template opAddAssign(T)
template opSubAssign(T)
template opMulAssign(T)
template opDivAssign(T)
template opModAssign(T)
template opAndAssign(T)
template opOrAssign(T)
template opXorAssign(T)
template opShlAssign(T)
template opShrAssign(T)
template opUShrAssign(T)
template opCatAssign(T)
ditto

ditto

VariantN opMul(T rhs);
ditto

ditto

template opIndex(K)
template opIndexAssign(T,N)
配列および連想配列演算です。VariantN が(連想)配列を格納している場合、 添え字に対応する値が取り出せます。それ以外の場合は例外を投げます。

Example:
 auto a = Variant(new int[10]);
 a[5] = 42;
 assert(a[5] == 42);
 int[int] hash = [ 42:24 ];
 a = hash;
 assert(a[42] == 24);


Caveat:
現在のD言語の制限により、読み込んで変更して書き換える演算、つまり op= は正しく動作しません:

 Variant a = new int[10];
 a[5] = 42;
 a[5] += 8;
 assert(a[5] == 50); // fails, a[5] is still 42


VariantN opIndex(K i);
配列および連想配列演算です。VariantN が(連想)配列を格納している場合、 添え字に対応する値が取り出せます。それ以外の場合は例外を投げます。

Example:
 auto a = Variant(new int[10]);
 a[5] = 42;
 assert(a[5] == 42);
 int[int] hash = [ 42:24 ];
 a = hash;
 assert(a[42] == 24);


Caveat:
現在のD言語の制限により、読み込んで変更して書き換える演算、つまり op= は正しく動作しません:

 Variant a = new int[10];
 a[5] = 42;
 a[5] += 8;
 assert(a[5] == 50); // fails, a[5] is still 42


size_t length();
VariantN が(連想)配列を格納している場合、 その配列の長さが取り出せます。 それ以外の場合は例外を投げます。

template opApply(Delegate) if (is(Delegate == delegate))
VariantN が配列を格納している場合、dg を配列の各要素に適用します。 そうでない場合、例外を投げます。

template Algebraic(T...)
Algebraic データ型は、あらかじめ指定した型のみに格納対象を制限します。 これは、VariantN を適切に計算した最大サイズとともにインスタンス化したものへのaliasです。Algebraic は、より簡潔でより効率的な操作のために 格納する型を制限したい場合に 適しています。

将来的には、 格納されている可能性のある型すべてについてユーザーコードで処理されているかをコンパイル時チェックして、 エラーを大幅に減らすような機能の追加を考えています。

BUGS:
現在のところ、Algebraic で再帰的なデータ型を定義することはできません。 この制限は将来的には取り除かれる予定です。

Example:
 auto v = Algebraic!(int, double, string)(5);
 assert(v.peek!(int));
 v = 3.14;
 assert(v.peek!(double));
 // auto x = v.peek!(long); // コンパイルエラー。long は入らない
 // v = '1'; // コンパイルエラー。char は入らない


alias Variant;
VariantVariantNcreal, char[], void delegate() のうち最大の型でインスタンス化したもののaliasです。これによって Variant は数値型,ポインタ,デリゲート,クラス参照を含む Dの基本型全てを格納できるサイズを持つことが保証されます。 それより大きな構造体を格納したい場合や、小さな型しか格納したいのでメモリを節約したい場合などは VariantN を直接使って最大値指定することを考慮に入れてください。

Variant[] variantArray(T...)(T args);
args から構築したVariantの配列を返します。

Example:
 auto a = variantArray(1, 3.14, "Hi!");
 assert(a[1] == 3.14);
 auto b = Variant(a); // variantの配列をvariantに格納
 assert(b[1] == 3.14);
std.boxer モジュールの boxArray 関数と似た機能が欲しい場合は、以下のように実装します:

 // old
 Box[] fun(...)
 {
     ...
     return boxArray(_arguments, _argptr);
 }
 // new
 Variant[] fun(T...)(T args)
 {
     ...
     return variantArray(args);
 }
これは意図的にこうなっています。 Variant の構築時には、 高速な処理のために格納する型の静的な型情報が必要となります。

class VariantException: object.Exception;
以下の3つのケースでこの例外が発生します。

  1. 未初期化のVariantが 代入, hasValue 以外で使われた場合
  2. getcoerce が非互換の型で呼び出された場合
  3. 比較できない値を格納した Variant を比較しようとした場合




TypeInfo source;
変換や比較の変換元

TypeInfo target;
変換や比較の変換先