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