Thread overview
Forwarding calls to objects of another type
Apr 10
Basile B.
April 10
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)()"

April 10
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.


April 11
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/
April 19
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. :)

>> [...]
>
> [...]

April 19
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.