std.bind for D2.0 (2)
たぶんまともなやり方じゃないけど,bindAlias された擬似関数のシンボルを指定してさらに bindAlias できるようになった.
微妙にごみが混ざっていてすまんけど,こんな感じ.
--- ~bind.d 2007-10-03 20:38:22.000000000 +0900 +++ bind.d 2007-10-04 16:08:42.000000000 +0900 @@ -263,7 +263,7 @@ } - char[] toString() { + string toString() { return "()"; } } @@ -310,13 +310,14 @@ static assert (i <= Params.length); static if (is(typeof(fn(params[0..i])))) { - const int res = i; + const int res_ = i; } else { - alias loop!(i+1).res res; + const int res_ = loop!(i+1).res_; } } - alias loop!().res res; + mixin loop!(); + alias res_ res; } /** Finds the minimal number of arguments a given function needs to be provided @@ -657,7 +658,8 @@ bind(&foo, tuple(23, 45)) --- */ -typeof(new BoundFunc!(FT, NullAlias, Tuple!(ArgList))) bind(FT, ArgList...)(FT fp, ArgList args) { +typeof(new BoundFunc!(FT, EmptySlot, Tuple!(ArgList))) bind(FT, ArgList...)(FT fp, ArgList args) { + //int a = new BoundFunc!(FT, EmptySlot, Tuple!(ArgList)); auto res = new DerefFunc!(ReturnType!(bind)); res.fp = fp; extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); @@ -665,6 +667,7 @@ } + /** bindAlias() is similar to bind(), but it's more powerful. Use bindAlias() rather than bind() where possible. <br/> @@ -690,19 +693,30 @@ Note: there is no bind-time check for reference nullness, there is however a call-time check on all references which can be disabled by using version=BindNoNullCheck or compiling in release mode. */ -template bindAlias(alias FT) { - typeof(new BoundFunc!(typeof(&FT), FT, Tuple!(ArgList))) bindAlias(ArgList...)(ArgList args) { - auto res = new DerefFunc!(ReturnType!(bindAlias)); - res.fp = &FT; - extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); - return res; - } +template bindAlias(alias FT) +{ + static if (__traits(hasMember, FT, "func")) // It means that if type of FT is BoundFunc!(...). + { + typeof(new BoundFunc!(typeof(&(FT.func)), FT.func, Tuple!(ArgList))) bindAlias(ArgList...)(ArgList args) { + auto res = new DerefFunc!(ReturnType!(bindAlias)); + res.fp = &(FT.func); + extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); + return res; + } + } + else + { + typeof(new BoundFunc!(typeof(&FT), FT, Tuple!(ArgList))) bindAlias(ArgList...)(ArgList args) { + auto res = new DerefFunc!(ReturnType!(bindAlias)); + res.fp = &FT; + extractBoundArgs!(0, 0, ArgList)(res.boundArgs, args); + return res; + } + } } - - /* Tells whether the specified type is a bound function */
テストコードはこちら.
import std.stdio, std.bind; void main() { writefln("-less (bind)"); bool less(int a, int b){return a<b;} auto less5 = bind(&less, _0, 5); foreach (i; 0..7) { writefln(i, "<5 ", less5(i)); } writefln("-greater (bind)"); auto greater = bind(&less, _1, _0); auto greater3 = bind(greater.ptr, _0, 3); foreach (i; 0..7) { writefln(i, ">3 ", greater3(i)); } writefln("-less (bindAlias)"); auto less2 = bindAlias!(less)(_0, 2); foreach (i; 0..7) { writefln(i, "<2 ", less2(i)); } writefln("-greater (bindAlias)"); auto greater4 = bindAlias!(greater)(_0, 4); foreach (i; 0..7) { writefln(i, ">4 ", greater4(i)); } /+ // これはまだエラーになる // 追記:いや当たり前だったw void foo() {writefln("foo");} void bar() {writefln("bar");} auto bindBindTest = bind(&foo, bind(&bar)); bindBindTest(); +/ }
__traits でごまかしているところからしてまともなやり方じゃないと思う.
まともなやり方だったら,最後の部分の関数合成もうまくいくだろうし.
デバッグ中に何度もこんなエラーが出てきたので,きっと bindAlias じゃなくて,traits.d の ParameterTypeTuple で擬似関数の層を吸収するんじゃないかなあと思うのだけど,まだよくわからない.
C:\D\dmd\bin\..\src\phobos\std\traits.d(68): alias std.traits.ParameterTypeTuple!(BoundFunc).ParameterTypeTuple recursive alias declaration C:\D\dmd\bin\..\src\phobos\std\traits.d(90): template instance std.traits.ParameterTypeTuple!(BoundFunc) error instantiating
誰か助けて.