汎用ファンクタ
できないと言っていた汎用ファンクタができてしまった。
ArgType の定義で、インスタンス化した TypeArray.typeAt に typeof をかけているのがミソ。
(TypeArray の定義は 5-23 のと同じ)
module doki.functor; import doki.typearray; class Functor(R, Args) { invariant { static assert(is (typeof(Args.length))); static assert( Args.length >= 10 && is (typeof(Args.typeAt!(9))) || Args.length >= 9 && is (typeof(Args.typeAt!(8))) || Args.length >= 8 && is (typeof(Args.typeAt!(7))) || Args.length >= 7 && is (typeof(Args.typeAt!(6))) || Args.length >= 6 && is (typeof(Args.typeAt!(5))) || Args.length >= 5 && is (typeof(Args.typeAt!(4))) || Args.length >= 4 && is (typeof(Args.typeAt!(3))) || Args.length >= 3 && is (typeof(Args.typeAt!(2))) || Args.length >= 2 && is (typeof(Args.typeAt!(1))) || Args.length >= 1 && is (typeof(Args.typeAt!(0))) ); } alias R ReturnType; alias Args ArgsType; template ArgType(int n) { alias typeof(Args.typeAt!(n)) ArgType; } alias ArgType!(0) Arg0Type; alias ArgType!(1) Arg1Type; alias ArgType!(2) Arg2Type; alias ArgType!(3) Arg3Type; alias ArgType!(4) Arg4Type; alias ArgType!(5) Arg5Type; alias ArgType!(6) Arg6Type; alias ArgType!(7) Arg7Type; alias ArgType!(8) Arg8Type; alias ArgType!(9) Arg9Type; template callOperator(int n : 1) { abstract ReturnType opCall(ArgType!(0)); } template callOperator(int n : 2) { abstract ReturnType opCall(ArgType!(0), ArgType!(1)); } ... mixin callOperator!(Args.length); }
で、実行。
import std.stdio; void main() { alias Functor!(bool, TypeArray!(int, char, double)) Arg3Functor; writefln(typeid(Arg3Functor.ArgsType)); writefln(typeid(typeof(Arg3Functor.ArgsType.typeAt!(0)))); writefln(typeid(typeof(Arg3Functor.ArgsType.typeAt!(1)))); writefln(typeid(typeof(Arg3Functor.ArgsType.typeAt!(2)))); writefln(typeid(Arg3Functor.ArgType!(0))); writefln(typeid(Arg3Functor.ArgType!(1))); writefln(typeid(Arg3Functor.ArgType!(2))); } ... TypeArray int char double int char double
ンマー、よかですな。
戻り値の型 bool、引数の型が int, char, double の opCall を持つ、関数オブジェクトの定義は以下のようになる。
class MyFunctor : Functor!(bool, TypeArray!(int, char, double)) { override ReturnType opCall( ArgType!(0) arg0, ArgType!(1) arg1, ArgType!(2) arg2 ) { ReturnType result = false; return result; } }
Functor を継承してナニいいことあんのよと言われそうだが、これを継承することによって、ReturnType と ArgType!(0〜n) の型 alias を持つことが保証され、汎用プログラミングがやりやすくなる。STL の関数オブジェクトが unary_function や binary_function を継承しているように。
writefln(typeid(MyFunctor)); writefln(typeid(MyFunctor.ReturnType)); writefln(typeid(MyFunctor.ArgsType)); writefln(MyFunctor.ArgsType.length); writefln(typeid(MyFunctor.ArgType!(0))); writefln(typeid(MyFunctor.ArgType!(1))); writefln(typeid(MyFunctor.ArgType!(2))); writefln(typeid(typeof(MyFunctor.opCall))); ... MyFunctor bool TypeArray 3 int char double bool()
といった具合。
TypeArray の実装が、羅列型のナサケナバージョンから変わる可能性はあるけど、どっちみち length と、typaAt テンプレートはつけるので、変わってもこちらに影響なし。