C#のジェネリッククラス

アバター
ナムアニクラウド
記事: 16
登録日時: 15年前
住所: 茨城県

C#のジェネリッククラス

投稿記事 by ナムアニクラウド » 14年前

 C#のジェネリッククラスの弱点の話。

 C#やJavaでいう「ジェネリクス」「ジェネリック」っていうのは、C++でいう「テンプレート」のことです。
C++のテンプレートはダックタイピングという方針の機能で、
テンプレート関数内では引数を使ってどんなメンバ呼び出しでも書けるようになっていて、
実行時にメンバが見つからないとエラーとなります(だったっけ?)。
下は+演算子というメンバ関数を勝手に使える例です。

CODE:

template void func( T arg )
{
    return arg + arg;    //+演算子が使えることにしておく
}
 対して、C#のジェネリクスは型制約を使って引数がどんなメンバを持っているか確定してから処理を書きます。
制約に引っかかるようなメンバ呼び出しをするとコンパイルエラーをもらいます。

CODE:

void func( T arg )
{
    return arg + arg;    //+演算子をそんなむやみに使うことは許されないんDA!
}
 さて、型制約とは、型Tはどんな型になれるかを限定するものです。
例えば、「Tはbaseクラスを継承している」と決めれば、baseクラスから継承できるメンバを使わせてもらえます。
こうすることで実行時エラーになる心配がなくなるわけです。
インターフェースという機能と連携して、「Tは値を比較できる」などの制約もできます。
上の例なら、「Tは+演算子が使える」と制約すればコンパイルできます。

 しかしこの機能、ちょっと弱点があって、
例えば複素数クラスを作ろうとしたときに、次のように実装しようとするのですが・・・

CODE:

class Complex
{
	//実数部分reと、虚数部分im
	public T re { get; set; }
	public T im { get; set; }

	public Complex( T real, T imaginary )
	{
		re = real;
		im = imaginary;
	}

	//複素数同士の加算
	public static Complex operator +( Complex lop, Complex rop )
	{
		return new Complex( lop.re + rop.re, lop.im + rop.im );
	}
}
これはコンパイルエラーです。
なぜかって? +演算子をオーバーロードしているところを見て欲しい。
lopとropのメンバre,imの型はそれぞれテンプレート型T。
つまり「勝手に+使っちゃダメよ」って言われているわけです。

 これではジェネリック複素数クラスはおろか、ジェネリックベクトルもジェネリック行列もできないのでは・・・
一応「式木」とかいろいろ使って解決できるらしいんですが、
結局制約に縛られまくって、使い心地のいいクラスが出来ません。できませんでした(涙)。
「四則演算をサポートしている」っていう型制約があればいいのになぁ。
自前でそういうインターフェースを作ったとしても、doubleやintに後付けはできないのよね。

コメントはまだありません。