www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing ref through a template chain

reply Steve Teale <steve.teale britseyeview.com> writes:
To bind variables, the MySQL api wants their addresses - in my tiny example
below, these are represented by the void*[].

If I just use something like setTarget in the example, it works fine, but then
when I try to set a bunch of them in one go I'm hosed because I can't get the
right addresses through the chain.

import std.stdio;

void*[2] vpa;

void setTarget(T)(ref T t, int i)
{
   vpa[i] = &t;
}

void setSeveral(T...)(ref T args)
{
   foreach (int i, arg; args)
      setTarget(&arg, i);
}

//ref.d|19|Error: variable i cannot be read at compile time|
//ref.d|19|Error: variable i cannot be read at compile time|
//ref.d|19|Error: Integer constant expression expected instead of cast(uint)i|
/*
void setSeveral2(T...)(ref T args)
{
   for (int i = 0; i < args.length; i++)
      setTarget(args[i], i);
}
*/

void main()
{
   bool a;
   int b;
   setSeveral(a, b);
   writefln("orig %x %x, set %x %x", &a, &b, vpa[0], vpa[1]); // addresses
differ
}

The problem arises I believe in 'foreach (int i, arg; args)' which makes a
copy for 'arg'. Usually in a foreach I can get round that by making it 'ref
arg'. But in the template function that does not work.

I can't use the setSeveral2() form, because that provokes the errors shown in
the comments.

How can I force the real addresses through the chain?

Thanks
Steve
Oct 03 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-10-03 15:08, Steve Teale wrote:
 To bind variables, the MySQL api wants their addresses - in my tiny example
 below, these are represented by the void*[].

 If I just use something like setTarget in the example, it works fine, but then
 when I try to set a bunch of them in one go I'm hosed because I can't get the
 right addresses through the chain.

 import std.stdio;

 void*[2] vpa;

 void setTarget(T)(ref T t, int i)
 {
     vpa[i] =&t;
 }

 void setSeveral(T...)(ref T args)
 {
     foreach (int i, arg; args)
        setTarget(&arg, i);
 }

 //ref.d|19|Error: variable i cannot be read at compile time|
 //ref.d|19|Error: variable i cannot be read at compile time|
 //ref.d|19|Error: Integer constant expression expected instead of cast(uint)i|
 /*
 void setSeveral2(T...)(ref T args)
 {
     for (int i = 0; i<  args.length; i++)
        setTarget(args[i], i);
 }
 */

 void main()
 {
     bool a;
     int b;
     setSeveral(a, b);
     writefln("orig %x %x, set %x %x",&a,&b, vpa[0], vpa[1]); // addresses
differ
 }

 The problem arises I believe in 'foreach (int i, arg; args)' which makes a
 copy for 'arg'. Usually in a foreach I can get round that by making it 'ref
 arg'. But in the template function that does not work.

 I can't use the setSeveral2() form, because that provokes the errors shown in
 the comments.

 How can I force the real addresses through the chain?

 Thanks
 Steve

Does this work: void setSeveral(T...)(ref T args) { foreach (i, _; args) setTarget(args[i], i); } Or you already tried that in setSeveral2. -- /Jacob Carlborg
Oct 03 2011
parent Steve Teale <steve.teale britseyeview.com> writes:
Works like a charm, and it's so obvious a thing to try that I'm kicking myself.

Thanks
Steve
Oct 03 2011