www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template alias parameters to local variables

reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
Consider the following code:

       alias Sink = scope void delegate(const(char)[]);

       private template generateAliases(int __i, __vars...) {
           import std.conv : to;

           static if(__i < __vars.length)
               enum generateAliases = "alias " ~
__vars[__i].stringof ~ " =
                    __vars[" ~ __i.to!string ~ "];\n" ~
                    generateAliases!(__i+1, __vars);
           else
               enum generateAliases = "";
       }

       template render(string __tpl, __vars...) {
           void render(Sink sink) {
               static void render2(string __tpl2, __vars2...)(Sink
sink2 = sink) {
                   .render!(__tpl2, __vars2)(sink2);
               }
               void render3(string __tpl2, __vars2...)(Sink sink2 =
sink) {
                   .render!(__tpl2, __vars2)(sink2);
               }

               alias __sink = sink;

               mixin(generateAliases!(0, __vars));
               //mixin(generateRenderer(__tpl));

               alias x = __vars[0];
               alias y = __vars[1];
			
               render2!("...", x, y);    // ERROR
               render3!("...", x, y);    // ERROR
           }
       }

       void main() {
           import std.stdio;
           int a, b;
           render!("...", a, b)(s => write(s));
       }

Inside the `render` function, which takes a string and several
variables as template parameters, as well as a delegate as
runtime parameter, I want another function to be available, which
should again accept a string and several aliases (including some
that `render` previously received as aliases). At the same time,
the function should implicitly pick up the sink that has been
passed to `render`. I'm trying to slightly different
implementations, `render2` and `render3`. They both produce
compile errors:

render2:
test.d(16): Error: static function test.main.render!("...", a,
b).render2 cannot access frame of function D main
test.d(29): Error: static function test.main.render!("...", a,
b).render2 cannot access frame of function D main

render3:
test.d(30): Error: template instance render3!("...", a, b) cannot
use local 'a' as parameter to non-global template render3(string
__tpl2, __vars2...)(Sink sink2 = sink)

I would prefer `render2`, because it is static and thus doesn't
need to allocate a context for the sink. Indeed, it used to
work before this issue was fixed:
https://issues.dlang.org/show_bug.cgi?id=11946
https://github.com/D-Programming-Language/dmd/pull/3884

Now, has this fix gone too far? On first glance, the `render2`
error message seems to make sense, but why doesn't the same error
occur for `render`?

However, why doesn't at least `render3` work? It's strange local
templates cannot accept local variables as aliases...

Alternatively, does anyone know of another way to achieve what I
want?
Sep 13 2014
next sibling parent reply "Kagamin" <spam here.lot> writes:
Doesn't this cause infinite recursion?
Sep 14 2014
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 14 September 2014 at 09:29:16 UTC, Kagamin wrote:
 Doesn't this cause infinite recursion?
No, because the inner templates are instantiated with different first template parameters. Even if all template parameters were the same, it would only be a runtime recursion.
Sep 14 2014
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Saturday, 13 September 2014 at 11:34:01 UTC, Marc Schütz wrote:
 Consider the following code:

       alias Sink = scope void delegate(const(char)[]);

       private template generateAliases(int __i, __vars...) {
           import std.conv : to;

           static if(__i < __vars.length)
               enum generateAliases = "alias " ~
 __vars[__i].stringof ~ " =
                    __vars[" ~ __i.to!string ~ "];\n" ~
                    generateAliases!(__i+1, __vars);
           else
               enum generateAliases = "";
       }

       template render(string __tpl, __vars...) {
           void render(Sink sink) {
               static void render2(string __tpl2, 
 __vars2...)(Sink
 sink2 = sink) {
                   .render!(__tpl2, __vars2)(sink2);
               }
               void render3(string __tpl2, __vars2...)(Sink 
 sink2 =
 sink) {
                   .render!(__tpl2, __vars2)(sink2);
               }

               alias __sink = sink;

               mixin(generateAliases!(0, __vars));
               //mixin(generateRenderer(__tpl));

               alias x = __vars[0];
               alias y = __vars[1];
 			
               render2!("...", x, y);    // ERROR
               render3!("...", x, y);    // ERROR
           }
       }

       void main() {
           import std.stdio;
           int a, b;
           render!("...", a, b)(s => write(s));
       }

 Inside the `render` function, which takes a string and several
 variables as template parameters, as well as a delegate as
 runtime parameter, I want another function to be available, 
 which
 should again accept a string and several aliases (including some
 that `render` previously received as aliases). At the same time,
 the function should implicitly pick up the sink that has been
 passed to `render`. I'm trying to slightly different
 implementations, `render2` and `render3`. They both produce
 compile errors:

 render2:
 test.d(16): Error: static function test.main.render!("...", a,
 b).render2 cannot access frame of function D main
 test.d(29): Error: static function test.main.render!("...", a,
 b).render2 cannot access frame of function D main

 render3:
 test.d(30): Error: template instance render3!("...", a, b) 
 cannot
 use local 'a' as parameter to non-global template render3(string
 __tpl2, __vars2...)(Sink sink2 = sink)

 I would prefer `render2`, because it is static and thus doesn't
 need to allocate a context for the sink. Indeed, it used to
 work before this issue was fixed:
 https://issues.dlang.org/show_bug.cgi?id=11946
 https://github.com/D-Programming-Language/dmd/pull/3884

 Now, has this fix gone too far? On first glance, the `render2`
 error message seems to make sense, but why doesn't the same 
 error
 occur for `render`?

 However, why doesn't at least `render3` work? It's strange local
 templates cannot accept local variables as aliases...

 Alternatively, does anyone know of another way to achieve what I
 want?
Anyone an idea?
Sep 17 2014