stdex.bind (2) - dmd 2.015
さっきのサンプルコードが全部通るようになったよ!
だけどstd.bindよりめちゃくちゃ短くなったと思って調べてみたら本来のstd.bindがやけに高機能だった件について.
次は型の調整に挑戦してみるよー.
あ,stdex.bindのソースは最後に張り付けときますね!
(追記:重複コードがたくさんあるけどtemplate/mixinではうまくいかない><;)
import std.stdio; import stdex.bind; T[] removeIf(alias cond, T)(T[] arr) { T[] ret; foreach (v; arr) if (!cond(v)) ret ~= v; return ret; } void main() { int[] arr = [1,2,3,4,5,6,7,8,9]; auto less = (int i, int j){return i<j;}; auto lessThan6 = bindAlias!(less)(_0, 6); auto greaterThan5 = bindAlias!(less)(5, _0); writefln(removeIf!(lessThan6)(arr)); writefln(removeIf!(greaterThan5)(arr)); static int sub(int a, int b){return a-b;}; auto a = bindAlias!(sub)(_0, _1); auto b = bindAlias!(sub)(_1, _0); auto c = bindAlias!(sub)(_0, 5); auto d = bindAlias!(sub)(10, _0); auto e = bindAlias!(sub)(10, 5); auto f = bindAlias!(sub)(_0, _0); writefln(a(10,5)); // 5 writefln(b(10,5)); // -5 writefln(c(10)); // 5 writefln(d(5)); // 5 writefln(e()); // 5 writefln(f(10)); // 0 ////////////////////////////////////////////// // 現在の制限 // /+ // 型の調整はできない auto z = (double a, int b){return a/b;}; writefln(bindAlias!(z)(_0,_0)(3)); // 0 +/ /+ // out/ref引数は扱えない auto f = (ref int a){a = 1;}; int x = 2; f(x); writefln(x); // 2 x = 3; auto fx = bindAlias!(f)(&x); fx(); writefln(x); // 3 +/ /+ // 関数合成はできない auto g = (int x, int y){return x*y;}; // g(x, y) = x * y auto h = (int x){return 2*x;}; // h(x) = 2 * x auto gh = bindAlias!(h)( bindAlias!(g)(_0, 3) ); // h(g(x, 3)) = h(x * 3) == 2 * (x * 3) writefln(gh(5)); // 30 +/ } /+ [6 7 8 9] [1 2 3 4 5] 5 -5 5 5 5 0 +/
module stdex.bind; import std.traits; import std.typetuple; struct DynArg(int i){static invariant uint id = i;} DynArg!(0) _0; DynArg!(1) _1; DynArg!(2) _2; DynArg!(3) _3; DynArg!(4) _4; DynArg!(5) _5; DynArg!(6) _6; DynArg!(7) _7; DynArg!(8) _8; DynArg!(9) _9; template NewParameterTuple(alias func, TL...) { alias typeof(TL) TL_; // 引数リストの何番目にDynArgがあるか enum indexDyn0 = indexOf!(DynArg!(0),TL_); //pragma(msg, indexDyn0); enum indexDyn1 = indexOf!(DynArg!(1),TL_); //pragma(msg, indexDyn1); enum indexDyn2 = indexOf!(DynArg!(2),TL_); //pragma(msg, indexDyn2); enum indexDyn3 = indexOf!(DynArg!(3),TL_); enum indexDyn4 = indexOf!(DynArg!(4),TL_); enum indexDyn5 = indexOf!(DynArg!(5),TL_); enum indexDyn6 = indexOf!(DynArg!(6),TL_); enum indexDyn7 = indexOf!(DynArg!(7),TL_); enum indexDyn8 = indexOf!(DynArg!(8),TL_); enum indexDyn9 = indexOf!(DynArg!(9),TL_); // 生関数の引数 alias ParameterTypeTuple!(func) Params; //pragma(msg, Params[indexDyn0]); //pragma(msg, Params[0]); //pragma(msg, Params[1]); // DynArgを使っている部分に対応するfuncの引数の型だけを得る static if (indexDyn0 == -1) alias void NewParams; else static if (indexDyn1 == -1) alias TypeTuple!(Params[indexDyn0]) NewParams; else static if (indexDyn2 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1]) NewParams; else static if (indexDyn3 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2]) NewParams; else static if (indexDyn4 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3]) NewParams; else static if (indexDyn5 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4]) NewParams; else static if (indexDyn6 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5]) NewParams; else static if (indexDyn7 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6]) NewParams; else static if (indexDyn8 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7]) NewParams; else static if (indexDyn9 == -1) alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7], Params[indexDyn8]) NewParams; else alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7], Params[indexDyn8], Params[indexDyn9]) NewParams; // //pragma(msg, NewParams); } class BoundFunc(alias func, TL...) { alias ReturnType!(func) RetValue; alias NewParameterTuple!(func, TL).NewParams NewParams; //pragma(msg,TL); //pragma(msg,RetValue); //pragma(msg,Params); TL args; this(TL args) { this.args = args; } alias ParameterTypeTuple!(func) Args; static if (is(NewParams == void)) { RetValue opCall() { return func(args); } } else { RetValue opCall(NewParams params) { static if (0 < Args.length) { static if (IsDynArg!(typeof(args[0]))) enum Arg0 = params[typeof(args[0]).id]; else enum Arg0 = args[0]; //pragma(msg,typeof(args)[0].id); //pragma(msg,NewParameterTuple!(func, TL).indexDyn0); } static if (1 < Args.length) { static if (IsDynArg!(typeof(args[1]))) enum Arg1 = params[typeof(args[1]).id]; else enum Arg1 = args[1]; //pragma(msg,typeof(args)[0].id); //pragma(msg,typeof(args)[1].id); //pragma(msg,Arg0); //pragma(msg,Arg1); //pragma(msg,NewParameterTuple!(func, TL).indexDyn1); } static if (2 < Args.length) { static if (IsDynArg!(typeof(args[2]))) enum Arg2 = params[typeof(args[2]).id]; else enum Arg2 = args[2]; } static if (3 < Args.length) { static if (IsDynArg!(typeof(args[3]))) enum Arg3 = params[typeof(args[3]).id]; else enum Arg3 = args[3]; } static if (4 < Args.length) { static if (IsDynArg!(typeof(args[4]))) enum Arg4 = params[typeof(args[4]).id]; else enum Arg4 = args[4]; } static if (5 < Args.length) { static if (IsDynArg!(typeof(args[5]))) enum Arg5 = params[typeof(args[5]).id]; else enum Arg5 = args[5]; } static if (6 < Args.length) { static if (IsDynArg!(typeof(args[6]))) enum Arg6 = params[typeof(args[6]).id]; else enum Arg6 = args[6]; } static if (7 < Args.length) { static if (IsDynArg!(typeof(args[7]))) enum Arg7 = params[typeof(args[7]).id]; else enum Arg7 = args[7]; } static if (8 < Args.length) { static if (IsDynArg!(typeof(args[8]))) enum Arg8 = params[typeof(args[8]).id]; else enum Arg8 = args[8]; } static if (9 < Args.length) { static if (IsDynArg!(typeof(args[9]))) enum Arg9 = params[typeof(args[9]).id]; else enum Arg9 = args[9]; } static if (Args.length == 1) return func(Arg0); else static if (Args.length == 2) return func(Arg0, Arg1); else static if (Args.length == 3) return func(Arg0, Arg1, Arg2, Arg3); else static if (Args.length == 4) return func(Arg0, Arg1, Arg2, Arg3, Arg4); else static if (Args.length == 5) return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5); else static if (Args.length == 6) return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); else static if (Args.length == 7) return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); else static if (Args.length == 8) return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8); else static if (Args.length == 9) return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9); else static assert(false);// 生関数の引数が多すぎます } } } template IsDynArg(T) { static if (is(T == DynArg!(0)) || is(T == DynArg!(1)) || is(T == DynArg!(2)) || is(T == DynArg!(3)) || is(T == DynArg!(4)) || is(T == DynArg!(5)) || is(T == DynArg!(6)) || is(T == DynArg!(7)) || is(T == DynArg!(8)) || is(T == DynArg!(9))) { enum IsDynArg = true; } else { enum IsDynArg = false; } } template bindAlias(alias func) { BoundFunc!(func, TL) bindAlias(TL...)(TL args) { return new BoundFunc!(func, TL)(args); } }