Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 29, 2018 Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
I hope this is understandable... I have:
class C {
void A();
void B();
void C();
}
I'm iterating over a set of objects of class C like:
foreach(obj; my_selected_objs){
...
}
The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc.
foreach(obj; my_selected_objs){
...
obj.A|B|C()
...
}
So, how can I write a generic handler that does the iteration, where I can specify which member function to call?
void do_A() {
handler(C.A()); ???
}
void do_B() {
handler(C.B()); ???
}
handler(???){
foreach(obj: my_selected_objs){
???
}
}
Viele Grüsse.
--
Robert M. Münch
http://www.saphirion.com
smarter | better | faster
|
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On 06/29/2018 09:44 AM, Robert M. Münch wrote:
> So, how can I write a generic handler that does the iteration, where I can specify which member function to call?
Passing a lambda or a string mixin:
import std.stdio;
class C {
void A() {
writeln(__FUNCTION__);
}
void B() {
writeln(__FUNCTION__);
}
}
void handler(alias func)(C[] cs) {
foreach (c; cs) {
func(c);
}
}
void handler_2(string func)(C[] cs) {
foreach (c; cs) {
enum expr = "c." ~ func ~ "();";
mixin(expr);
}
}
void main() {
auto cs = [ new C(), new C() ];
handler!(o => o.A())(cs);
handler!(o => o.B())(cs);
handler_2!"A"(cs);
handler_2!"B"(cs);
}
Ali
|
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said: > On 06/29/2018 09:44 AM, Robert M. Münch wrote: > >> So, how can I write a generic handler that does the iteration, where I can specify which member function to call? > > Passing a lambda or a string mixin: Hi, that was somehow in my mind but didn't made to get the syntax clear... Thanks a lot. > import std.stdio; > > class C { > void A() { > writeln(__FUNCTION__); > } > > void B() { > writeln(__FUNCTION__); > } > } > > void handler(alias func)(C[] cs) { > foreach (c; cs) { > func(c); > } > } Is it possible to make C[] a template type so that I can use different classes and lambdas? > void handler_2(string func)(C[] cs) { > foreach (c; cs) { > enum expr = "c." ~ func ~ "();"; > mixin(expr); > } > } Ok, the "strange" syntax for me is the handler(alias func) or handler(string func) ... I'm alway thinkin in lines of a parameter... which of course doesn't work. Looking at the D grammer for functions these things should be the FuncDeclaratorSuffix, is this right? And then, which part does this fall into? FuncDeclaratorSuffix: Parameters MemberFunctionAttributesopt TemplateParameters Parameters MemberFunctionAttributesop -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On Friday, 29 June 2018 at 20:08:56 UTC, Robert M. Münch wrote: > On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said: > >> On 06/29/2018 09:44 AM, Robert M. Münch wrote: >> void handler(alias func)(C[] cs) { >> foreach (c; cs) { >> func(c); >> } >> } > > Is it possible to make C[] a template type so that I can use different classes and lambdas? My guess would be: void handler(alias func, T)(T[] ts) { .... } > > Ok, the "strange" syntax for me is the handler(alias func) or handler(string func) ... I'm alway thinkin in lines of a parameter... which of course doesn't work. > > Looking at the D grammer for functions these things should be the FuncDeclaratorSuffix, is this right? And then, which part does this fall into? > > FuncDeclaratorSuffix: > Parameters MemberFunctionAttributesopt > TemplateParameters Parameters MemberFunctionAttributesop It's definitely the "TemplateParameters" one: void func(<template params>)(<params>) { ... } is the short form of template(<template params>) { void func(<params>) { ... } } https://dlang.org/spec/template.html |
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote: > I hope this is understandable... I have: > > class C { > void A(); > void B(); > void C(); > } > > I'm iterating over a set of objects of class C like: > > foreach(obj; my_selected_objs){ > ... > } > > The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc. > > foreach(obj; my_selected_objs){ > ... > obj.A|B|C() > ... > } > > So, how can I write a generic handler that does the iteration, where I can specify which member function to call? > > void do_A() { > handler(C.A()); ??? > } > > void do_B() { > handler(C.B()); ??? > } > > handler(???){ > foreach(obj: my_selected_objs){ > ??? > } > } > > Viele Grüsse. Trying to fiddle around a bit with delegates.. But why is the context for delegates not working for classes?? https://run.dlang.io/is/Rxeukg import std.stdio; class Aclass { int i; void foo() { writeln("called ", i); } } struct Bstruct { int i; void foo() { writeln("called ", i); } } template callFoo(T) { alias Dun = void delegate(); void callFoo(T t) { Dun fun; fun.funcptr = &T.foo; fun.ptr = cast(void*)(&t); Dun gun; gun = &t.foo; writeln(fun.ptr, " (fun.ptr of " ~ T.stringof ~ ")"); writeln(gun.ptr, " (gun.ptr of " ~ T.stringof ~ ")"); writeln(&t, " (Address of instance (context))"); fun(); gun(); } } void main() { auto a = new Aclass(); a.i = 5; auto b = Bstruct(); b.i = 7; writeln("---- Doesn't work ----"); callFoo(a); writeln("\n---- Works ----"); callFoo(b); } |
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Friday, 29 June 2018 at 20:28:55 UTC, Timoses wrote:
> On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote:
>
> Trying to fiddle around a bit with delegates.. But why is the context for delegates not working for classes??
Aw.. Class = reference type so
class A { }
struct B { }
void delegate() del;
A a = new A();
del.ptr = a; // NOT its address, as that would be the address of the reference on the stack
B b = B();
del.ptr = &b // value type => address of object in stack
... How would one print the address of the object then though?
Since &a is the address of the reference' types stack location.
cast(void*)a
would be on solution I guess.
|
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | How does it work if one of the members takes an argument that is deduced inside the handler function? On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said: > Passing a lambda or a string mixin: > > import std.stdio; > > class C { > void A() { > writeln(__FUNCTION__); > } > > void B() { > writeln(__FUNCTION__); > } void C(bool flag) { writln(__FUNCTION__): } > } > > void handler(alias func)(C[] cs) { > foreach (c; cs) { > func(c); func(c)(flag); > } > } > > void handler_2(string func)(C[] cs) { > foreach (c; cs) { > enum expr = "c." ~ func ~ "();"; > mixin(expr); > } > } > > void main() { > auto cs = [ new C(), new C() ]; > > handler!(o => o.A())(cs); How to get the parameter spec into the lambda? > handler!(o => o.B())(cs); > > handler_2!"A"(cs); > handler_2!"B"(cs); > } > > Ali -- Robert M. Münch http://www.saphirion.com smarter | better | faster |
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On 06/29/2018 02:40 PM, Robert M. Münch wrote: > How does it work if one of the members takes an argument that is deduced > inside the handler function? > > > On 2018-06-29 18:05:00 +0000, Ali ‡ehreli said: > >> Passing a lambda or a string mixin: >> >> import std.stdio; >> >> class C { >> void A() { >> writeln(__FUNCTION__); >> } >> >> void B() { >> writeln(__FUNCTION__); >> } > > void C(bool flag) { > writln(__FUNCTION__): > } So the others still don't have a parameter? It's not clear how the general function should know what member function is being passed. One way is to check the signature of the lambda and decide to pass the flag or not. The other way is to always pass the flag but the caller does not use it. import std.stdio; class C { void A() { writeln(__FUNCTION__); } void B() { writeln(__FUNCTION__); } void C(bool flag) { writeln(__FUNCTION__); } } void handler(alias func)(C[] cs) { bool flag; foreach (c; cs) { func(c, flag); // Always passes the flag } } void main() { auto cs = [ new C(), new C() ]; // flag is used only sometimes handler!((o, flag) => o.A())(cs); handler!((o, flag) => o.B())(cs); handler!((o, flag) => o.C(flag))(cs); } But it started to feel unnatural at this point. What is the exact use case? Perhaps there are better ways... Ali |
June 30, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert M. Münch | On Friday, 29 June 2018 at 16:44:36 UTC, Robert M. Münch wrote:
> I hope this is understandable... I have:
>
> class C {
> void A();
> void B();
> void C();
> }
>
> I'm iterating over a set of objects of class C like:
>
> foreach(obj; my_selected_objs){
> ...
> }
>
> The iteration and code before/afterwards always looks the same, I need this iteration for many of the memember functions like C.A() and C.B(), etc.
>
> foreach(obj; my_selected_objs){
> ...
> obj.A|B|C()
> ...
> }
>
> So, how can I write a generic handler that does the iteration, where I can specify which member function to call?
>
> void do_A() {
> handler(C.A()); ???
> }
>
> void do_B() {
> handler(C.B()); ???
> }
>
> handler(???){
> foreach(obj: my_selected_objs){
> ???
> }
> }
>
> Viele Grüsse.
Using opDispatch we can manage to get a voldemort able to resolve the member func A, B or C etc.
---
import std.stdio;
class C
{
void A(){writeln(__FUNCTION__);}
void B(int i){writeln(__FUNCTION__, " ", i);}
}
auto handler(T)(T t)
{
struct Handler
{
auto opDispatch(string member, Args...)(Args args)
{
import std.algorithm.iteration : each;
mixin( `t.each!(a => a.` ~ member ~ `(args));` );
}
}
Handler h;
return h;
}
void main()
{
auto cs = [new C(), new C()];
handler(cs).A();
cs.handler.B(42); // UFCS style
}
---
which results a very natural expression.
|
June 29, 2018 Re: Call different member functions on object sequence with a generic handler function? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On 06/29/2018 02:11 PM, Timoses wrote: > .... How would one print the address of the object then though? > Since &a is the address of the reference' types stack location. Casting the reference to void* produces the address of the object: import std.stdio; class C { int i; } void main() { auto r = new C(); writeln("Reference is at ", &r); writeln("Object is at ", cast(void*)r); writeln("Member is at ", &r.i); } Sample output: Reference is at 7FFE735E6698 Object is at 7F78F02B0060 Member is at 7F78F02B0070 Ali |
Copyright © 1999-2021 by the D Language Foundation