...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

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

誰か助けて.