Copying a variable state in a delegate literal definition

Steven Schveighoffer schveiguy at yahoo.com
Fri Sep 2 13:29:05 PDT 2011


On Fri, 02 Sep 2011 14:29:18 -0400, Andrej Mitrovic  
<andrej.mitrovich at gmail.com> wrote:

> So I have this code right here (semi-pseudocode) inside a "MenuBar"  
> widget:
>
> void showMenu(index menuIndex) { }
> void appendMenuButton()
> {
>     static size_t menuIndex;
>     // create menu button, and then:
>     button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };
>     menuIndex++;
> }
>
> button is a newly constructed widget object, Signal is just an enum.
> Inside of my Widget class I have this:
>
>     void delegate()[] clickHandlers;
>
>     @property void connect(Signal signal)(void delegate() dg)
>     {
>         static if (signal == Signal.MouseClick)
>             clickHandlers ~= dg;
>         else
>             // ...
>     }
>
>     void onClicked()
>     {
>         foreach (handler; clickHandlers)
>         {
>             handler();
>         }
>     }
>
> So far so good. This works except for the following quirk:
>
> button.connect!(Signal.MouseClick) = { this.showMenu(menuIndex); };
>
> Inside this lambda menuIndex is accessed through that frame pointer
> when the lambda is called. But I actually want a *copy* of menuIndex
> at the definition site. Because as I call appendMenuButton() numerous
> times, menuIndex is increased, so if I do this:
>
> menu.appendMenuButton();
> menu.appendMenuButton();
>
>  { this.showMenu(menuIndex); }; becomes:
>  { this.showMenu(2); };
>
> when it is called. I can't use a function literal instead of a
> delegate literal because I want to have access to "this.showMenu", but
> I want a copy of menuIndex. I've tried this:
>
> { size_t index = menuIndex; writeln(index); }
>
> However that doesn't copy the state either, it initializes index with
> the menuIndex in the frame pointer when the literal is called.
>
> So how can I selectively copy the state of some variables at the site
> of the definition of a delegate literal?

Am I missing something, or is it this simple?

void appendMenuButton()
{
    static size_t menuIndex;
    auto frameIndex = menuIndex++;
    button.connect!(Signal.MouseClick) = { this.showMenu(frameIndex); };
}

-Steve


More information about the Digitalmars-d-learn mailing list