Forwarding calls to objects of another type

Basile B. via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Apr 10 14:27:34 PDT 2017


On Monday, 10 April 2017 at 21:04:10 UTC, Johan Fjeldtvedt wrote:
> I have a couple of questions related to the following code: 
> https://gist.github.com/Jaffe-/b027287a884fc2e173a65601ec242676
>
> 1) This is a very simplified example, but what I'm trying to do 
> here is to call `foo` on each object in `Container.ss` contains 
> when `foo` is called, and likewise for `bar`. To do this 
> without having to repeat the foreach loop in every member 
> function, I made the `call_for_each` template. However, I found 
> no other way to pull this off (without using string mixins) 
> than to also add the `call` template in the S struct. At first 
> I thought it would be possible to write `s.func(args)` in 
> `call_for_each`, but that will try to look up func as a member 
> in the struct.
>
> Is there a more common / idiomatic way of doing this? In C++ 
> this would be solved by using a member function pointer as a 
> template argument, but as far as I understand D uses delegates 
> (which are already bound to an instance) instead?

One way:

struct S {
     int x[];

     void foo(int x) {
         this.x ~= x;
     }

     void bar() {
         writeln("Contains: ", x);
     }

     auto call(alias func, T...)(T args) {
         return func(args);
     }

     auto reduce(alias func)() {
         return x.reduce!(func);
     }
}

class Container {
     S[10] ss;

     void dispatch(string func, T...)(T args) {
         foreach(ref s; ss) {
             __traits(getMember, s, func)(args);
         }
     }

     auto reduce(alias func)() {
         return ss[]
             .map!(t => t.reduce!func)
             .reduce!(func);
     }

}

void main() {
     auto test = new Container();

     test.dispatch!"foo"(10);
     test.dispatch!"foo"(20);
     test.dispatch!"foo"(30);
     test.dispatch!"bar"();
     //auto x = test.reduce!((a, b) => a + b);
     auto x = test.reduce!((int a, int b) => a + b);  // Compiles
     writeln(x);
}

Another way would be to take the delegate of one instance and to 
patch the pointer to the instance for each instance (because the 
member of a delegate can be changed: .ptr -> instance, .funcptr 
-> static address of the function). But it's less clean.

> 2) This is about the reduce templates. As I've commented, I 
> can't use a template lambda with reduce, but I can use a lambda 
> taking ints as arguments. Why is this? The error message I get 
> when using the template lambda is:
>
> "template instance reduce!((a, b) => a + b) cannot use local 
> '__lambda1' as parameter to non-global template reduce(alias 
> fun)()"

No idea for this.




More information about the Digitalmars-d-learn mailing list