www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D equivalent of C++ bind ?

reply chmike <christophe meessen.net> writes:
Is there an equivalent in D of the C++11 std.bind template class 
[http://en.cppreference.com/w/cpp/utility/functional/bind] ?

Here is a blog post showing different examples of its use
https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/


A possible use case is for a callback function/delegate with the 
expected signature bool cb(int error). I would like to pass a 
function bool myCb(int error, ref int myArg) instead with the 
variable myArg being given as predefined argument.

Here is an example.
----
int count = 0;

bool myCb(int error, ref int myArg)
{
     if (myArg >= 6)
         return false;
     writeln(++myArg);
     return true;
}

void async_task(void function(int error) cb) { . . . while cb(0) 
. . . }

void main() {
     . . .
     async_task( ??? myCb ??? count ??? );
     . . .
}
----

In C++ we would write

async_task(std::bind(myCb, std::placeholders::_1, count));
May 10 2016
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
I know this really isn't what you want, but it may help you:

void doFunc(int a, int b, string text) {
	import std.stdio : writeln;
	writeln(text, ": ", a, " <> ", b);	
}

void receiver(void delegate(string text) del) {
	del("Hey");	
}

void main() {
	struct Binder {
		int a, b;
		void function(int, int, string) del;
		
		void call(string text) { del(a, b, text); }
	}
	
	Binder binder = Binder(1, 3, &doFunc);
	receiver(&binder.call);
}
May 10 2016
parent reply chmike <christophe meessen.net> writes:
Thanks. This does the job but it's not as concise.
May 10 2016
next sibling parent =?UTF-8?B?QW5kcsOp?= <Andre nospam.org> writes:
On Tuesday, 10 May 2016 at 15:33:03 UTC, chmike wrote:
 Thanks. This does the job but it's not as concise.
I've never missed C++'s bind functionality because D has first class support for delegates. If async_task is changed to the following: void async_task(void delegate(int error) cb) { . . . while cb(0) . . . } You could just adapt a call to it using a lambda function: async_task( (error) => myCb(error, count) ); D makes sure the enclosing stack is copied to the heap and count is reachable. Maybe this helps... Regards, André
May 10 2016
prev sibling parent Dsby <dushibaiyu yahoo.com> writes:
On Tuesday, 10 May 2016 at 15:33:03 UTC, chmike wrote:
 Thanks. This does the job but it's not as concise.
The std.functional.partial can not use in runtime, only on complier time. and it can not bind args that more than one.
May 12 2016
prev sibling next sibling parent Olivier Pisano <olivier.pisano laposte.net> writes:
Salut Christophe,

Did you have a look at 
https://dlang.org/phobos/std_functional.html#partial ?
May 10 2016
prev sibling next sibling parent Gary Willoughby <dev nomad.so> writes:
On Tuesday, 10 May 2016 at 09:39:53 UTC, chmike wrote:
 Is there an equivalent in D of the C++11 std.bind template class
See http://dlang.org/phobos/std_functional.html#partial
May 10 2016
prev sibling parent reply Dsby <dushibaiyu yahoo.com> writes:
On Tuesday, 10 May 2016 at 09:39:53 UTC, chmike wrote:
 Is there an equivalent in D of the C++11 std.bind template 
 class 
 [http://en.cppreference.com/w/cpp/utility/functional/bind] ?

 Here is a blog post showing different examples of its use
 https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/


 A possible use case is for a callback function/delegate with 
 the expected signature bool cb(int error). I would like to pass 
 a function bool myCb(int error, ref int myArg) instead with the 
 variable myArg being given as predefined argument.

 Here is an example.
 ----
 int count = 0;

 bool myCb(int error, ref int myArg)
 {
     if (myArg >= 6)
         return false;
     writeln(++myArg);
     return true;
 }

 void async_task(void function(int error) cb) { . . . while 
 cb(0) . . . }

 void main() {
     . . .
     async_task( ??? myCb ??? count ??? );
     . . .
 }
 ----

 In C++ we would write

 async_task(std::bind(myCb, std::placeholders::_1, count));
I write one, bind functon to a delegate. In here: https://github.com/putao-dev/collie/blob/master/source/collie/utils/functional.d this is the code: auto bind(T,Args...)(auto ref T fun,Args args) if (isCallable!(T)) { alias FUNTYPE = Parameters!(fun); static if(is(Args == void)) { static if(isDelegate!T) return fun; else return toDelegate(fun); } else static if(FUNTYPE.length > args.length) { alias DTYPE = FUNTYPE[args.length..$]; return delegate(DTYPE ars){ TypeTuple!(FUNTYPE) value; value[0..args.length] = args[]; value[args.length..$] = ars[]; return fun(value); }; } else { return delegate(){return fun(args);}; } }
May 12 2016
parent reply chmike <christophe meessen.net> writes:
On Thursday, 12 May 2016 at 10:38:37 UTC, Dsby wrote:

 I write one, bind functon to a delegate.

 In here:
 https://github.com/putao-dev/collie/blob/master/source/collie/utils/functional.d


 this is the code:

 auto  bind(T,Args...)(auto ref T fun,Args args) if 
 (isCallable!(T))
 {
     alias FUNTYPE = Parameters!(fun);
     static if(is(Args == void))
     {
         static if(isDelegate!T)
             return fun;
         else
             return toDelegate(fun);
     }
     else static if(FUNTYPE.length > args.length)
     {
         alias DTYPE = FUNTYPE[args.length..$];
         return
             delegate(DTYPE ars){
                 TypeTuple!(FUNTYPE) value;
                 value[0..args.length] = args[];
                 value[args.length..$] = ars[];
                 return fun(value);
             };
     }
     else
     {
         return delegate(){return fun(args);};
     }
 }
Thank you. Would you agree to help me understand it ? The only thing I don't understand is why the function template argument is defined as T and the argument as auto ref T fun. Why the auto ref and not alias T in the template argument list ? This bind is better than Partial!() from std.functional since it accepts any number of parameters. But the given parameters are passed as first arguments of fun. The std::bind of C++ allows to bind any parameter in any order and eventually multiple times. It's really as if a new function was defined with a total liberty degree on its signature. Anyway thank you very much.
May 16 2016
parent reply Dsby <dushibaiyu yahoo.com> writes:
On Monday, 16 May 2016 at 15:11:26 UTC, chmike wrote:
 On Thursday, 12 May 2016 at 10:38:37 UTC, Dsby wrote:

 [...]
Thank you. Would you agree to help me understand it ? The only thing I don't understand is why the function template argument is defined as T and the argument as auto ref T fun. Why the auto ref and not alias T in the template argument list ? This bind is better than Partial!() from std.functional since it accepts any number of parameters. But the given parameters are passed as first arguments of fun. The std::bind of C++ allows to bind any parameter in any order and eventually multiple times. It's really as if a new function was defined with a total liberty degree on its signature. Anyway thank you very much.
you can remove "auto ref". and I remove the "auto ref" in my use. if used the "alias T", It can not handle all while when the T is a delegate. in C++ std::bind, the arguments order you can sort by used. in D I do not find how to enablement.
May 16 2016
parent chmike <christophe meessen.net> writes:
On Monday, 16 May 2016 at 15:57:52 UTC, Dsby wrote:

 you can remove "auto ref". and I remove the "auto ref" in my 
 use.
 if used the "alias T", It can not handle all while when the T 
 is a delegate.

 in C++ std::bind, the arguments order you can sort by used. in 
 D I do not find how to enablement.
Yes this doesn't look easy. Maybe by using a mixin. Unfortunately this slows down compilation. I don't know the impact on optimization. I'm not sure if converting a function to a delegate is a good thing. It is good for your use case where the bind functions are used as callbacks. But sometime, users may really want to create a function. The user should then use ToDelegate! If he wants to convert the function to a delegate. But from the the documentation, ToDelegate doesn't work with functions with the safe attribute.
May 16 2016