www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Forwarding calls to objects of another type

reply Johan Fjeldtvedt <jaffe1 gmail.com> writes:
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?

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)()"
Apr 10 2017
parent reply Basile B. <b2.temp gmx.com> writes:
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.
Apr 10 2017
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Monday, 10 April 2017 at 21:27:34 UTC, Basile B. wrote:
 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.
The use of the global identity template will fix this: see https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/
Apr 10 2017
parent Johan Fjeldtvedt <jaffe1 gmail.com> writes:
On Tuesday, 11 April 2017 at 02:01:19 UTC, Nicholas Wilson wrote:
 On Monday, 10 April 2017 at 21:27:34 UTC, Basile B. wrote:
 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.
The use of the global identity template will fix this: see https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/
Thanks, that did work. I think I understand the point about UFCS lookup rules, but it still seems strange (it was at least surprising) that I couldn't use the template (a, b) => a + b in place of (int a, int b) => a + b.
Apr 19 2017
prev sibling parent Johan Fjeldtvedt <jaffe1 gmail.com> writes:
On Monday, 10 April 2017 at 21:27:34 UTC, Basile B. wrote:
 On Monday, 10 April 2017 at 21:04:10 UTC, Johan Fjeldtvedt 
 wrote:
 [...]
One way: [...]
Thanks for the reply. The traits way of doing it seems to be what I want. :)
 [...]
[...]
Apr 19 2017