advanced function binding

Kirk McDonald kirklin.mcdonald at gmail.com
Wed Mar 28 16:24:52 PDT 2007


Moritz Warning wrote:
>>http://paste.dprogramming.com/dpbaqugv.php
> 
> 
> Hi,
> 
> thank you for your response! It was very helpful indeed.
> Here is the example code I'm experimenting on:
> 
> import std.traits;
> import std.conv;
> import std.bind;
> 
> void main() {
> 	Wrapper!(A, Foo.getBar) x = new Wrapper!(A, Foo.getBar)(Foo.getBar);
> }
> 
> class Foo {
> 	void getBar() {}
> }
> class Bar { }
> 
> class Wrapper(B, alias Func)
> {
> 	alias ReturnType!(Func) R;
> 	alias typeof(Func) * FuncPtr;
> 	alias typeof(ReturnType!(std.bind.bindAlias!(Func)))  BindPtr; //type is DerefFunc!(R) or void?
> 	
> 	FuncPtr funcptr;
> 	BindPtr bindptr;
> 	
> 	//1. store pointer
> 	this(FuncPtr funcptr)
> 	{
> 		this.funcptr = funcptr;
> 	}
> 	
> 	//2. bind parameters
> 	void bind(char[][] u)
> 	{
> 		ParameterTypeTuple!(Func) t;
> 		foreach (i, arg; t) {
> 			t[i] = convert!(typeof(arg))(u[i]);
> 		}
> 		bindptr = std.bind.bindAlias!(Func)(t);
> 		//fn(t);
> 	}
> 	
> 	//3. call function on object
> 	R call(B b)
> 	{
> 		R delegate() dg; 
> 		dg.funcptr = this.funcptr; //need to assign bindptr!
> 		dg.ptr = cast(void*) b;
> 		return dg();
> 	}
> }
> 
> T convert(T)(char[] u)
> {
> 	static if (is(T == int)) {
> 		return std.conv.toInt(u);
> 	} else static if (is(T == float)) {
> 		return std.conv.toFloat(u);;
> 	} else static if (is(T == char[])) {
> 		return u;
> 	} else static assert(false, "Unsupported type: " ~ T.stringof);
> }
> 
> It doesn't compile because I cannot assign a bindAlias!(Func)(t) to bindptr.
> The compiler tells me the return type of bindAlias is void, when I look at the source
> I would guess it's DerefFunc!(R). Anyway, somehow I must be able to store the binded
> function and assign it to dg.funcptr in call().
> What is going wrong?

D distinguishes between function types and function pointer types. That 
is, given this:

void foo() {}

The following are different types:

typeof(foo)
typeof(&foo)

The former is a function type, and is not actually that useful. (You 
can't declare variables of this type, or use it as a function parameter 
or return type.) The latter is a function pointer, and is very useful. 
In that example, it is equivalent to the type "void function()".

If you want to get a pointer to a function in D, you MUST use the 
address-of operator (as in &foo). Thus, the line:
     alias typeof(Func) * FuncPtr;
should actually be:
     alias typeof(&Func) FuncPtr;

You are passing the function to the class as both an alias template 
argument and a constructor argument. It is then available both as a 
template argument, and as a member variable. This seems redundant. 
Supplying it as a template argument is probably preferable. Furthermore, 
experience has shown me it is wise to allow the user to explicitly 
specify the type of the function. Thus, FuncPtr should actually be a 
third template parameter, like this:

class Wrapper(B, alias Func, FuncPtr = typeof(&Func)) {}

You can then dispense with the constructor and the funcptr member 
variable entirely.

Next, do you really need to store the /converted/ arguments? Why not 
just store the char[][], and convert the arguments when the function is 
actually called? The class looks like this if you do that:

class Wrapper(B, alias Func, FuncPtr = typeof(&Func) {
     alias ReturnType!(FuncPtr) R;
     alias ParameterTypeTuple!(FuncPtr) Params;
     char[][] args;
     void bind(char[][] u) {
         args = u;
     }
     R call(B b) {
         R delegate(Params) dg;
         dg.funcptr = &Func;
         dg.ptr = cast(void*)b;
         Params t;
         foreach (i, arg; t) {
             t[i] = convert!(typeof(arg))(this.args[i]);
         }
         return dg(t);
     }
}

Note that std.bind is not needed at all if it is done this way.

-- 
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org


More information about the Digitalmars-d-learn mailing list