Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 12, 2020 how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
e.g. int[] a = new int[la]; int[] b = new int[lb]; int[] c = new int[lc]; int[] d = new int[ld]; the func I want to write, e.g. for 2 arrays (instantiation) is like this: void print_random_elem_addr(int[] x, int[] y) { auto i = random_int_between(0, x.length); auto j = random_int_between(0, y.length); print(&(x[i], &(y[j])); // only single print() func call allowed! } But I want one generic function, which can be called as: print_random_elem_addr(a, b); print_random_elem_addr(a, b, c); print_random_elem_addr(a, b, c, d); ... My main question is how to meta-program (generate the parameter list) this line: print(&(x[i], &(y[j])); // only single print() func call allowed! Thanks! |
September 11, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On 9/11/20 6:44 PM, mw wrote:> e.g. > > int[] a = new int[la]; > int[] b = new int[lb]; > int[] c = new int[lc]; > int[] d = new int[ld]; > > > the func I want to write, e.g. for 2 arrays (instantiation) is like this: > > void print_random_elem_addr(int[] x, int[] y) { > auto i = random_int_between(0, x.length); > auto j = random_int_between(0, y.length); > print(&(x[i], &(y[j])); // only single print() func call allowed! > } > > > But I want one generic function, which can be called as: > > print_random_elem_addr(a, b); > print_random_elem_addr(a, b, c); > print_random_elem_addr(a, b, c, d); If they are all of same type like int[] in this case, then you can variable number of parameters, which means "any number of int[] arrays" below, elements of which can be called either as separate arguments or as a single array argument: import std.stdio; import std.random; void print_random_elem_addr(int[][] arrays...) { foreach (i, array; arrays) { const chosen = uniform(0, array.length); writefln!"Array %s, element %s: %s"(i, chosen, &array[chosen]); } } void main() { auto randomLengthArray() { return new int[uniform(1, 101)]; } auto a = randomLengthArray(); auto b = randomLengthArray(); auto c = randomLengthArray(); writeln("As independent arguments:"); print_random_elem_addr(a, b, c); writeln("As a single argument:"); print_random_elem_addr([a, b, c]); } Warning: The array that is automatically generated by the first print_random_elem_addr() call in main() is short-lived: You cannot store a slice of it because the array that contains the arguments may be destroyed upon leaving the function (e.g. in the "independent" case above). Here is some more information: http://ddili.org/ders/d.en/parameter_flexibility.html#ix_parameter_flexibility.variadic%20function There are other ways of doing the same thing. For example, if you want to work with different ranges, you can use tuple template parameters: http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.tuple%20template%20parameter Ali |
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Saturday, 12 September 2020 at 03:11:09 UTC, Ali Çehreli wrote: > On 9/11/20 6:44 PM, mw wrote:> e.g. > > > > int[] a = new int[la]; > > int[] b = new int[lb]; > > int[] c = new int[lc]; > > int[] d = new int[ld]; > > > > > > the func I want to write, e.g. for 2 arrays (instantiation) > is like this: > > > > void print_random_elem_addr(int[] x, int[] y) { > > auto i = random_int_between(0, x.length); > > auto j = random_int_between(0, y.length); > > print(&(x[i], &(y[j])); // only single print() func call > allowed! > > } > > > > > > But I want one generic function, which can be called as: > > > > print_random_elem_addr(a, b); > > print_random_elem_addr(a, b, c); > > print_random_elem_addr(a, b, c, d); Thanks for the reply. > If they are all of same type like int[] in this case, then you but, this is not the intention, we should suppose the array's are heterogeneous type ... > can variable number of parameters, which means "any number of int[] arrays" below, elements of which can be called either as separate arguments or as a single array argument: > > import std.stdio; > import std.random; > > void print_random_elem_addr(int[][] arrays...) { ... to prevent passing in parameters as array of array like this. > foreach (i, array; arrays) { > const chosen = uniform(0, array.length); > writefln!"Array %s, element %s: %s"(i, chosen, &array[chosen]); actually this writefln will be called n times. I intentionally require: print(&(x[i], &(y[j])); // only single print() func call allowed! I.e. I want to learn the generic meta-programming way to assemble such parameter list (&(x[i], &(y[j])) at compile time, it is possible? |
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 12 September 2020 at 03:19:23 UTC, mw wrote: > I.e. I want to learn the generic meta-programming way to assemble such parameter list (&(x[i], &(y[j])) at compile time, it is possible? It's possible if you use a helper function. Here's how: import std.meta: allSatisfy; import std.traits: isArray; void printRandomElemAddr(Arrays...)(Arrays arrays) if (allSatisfy!(isArray, Arrays)) { auto randomElemAddr(size_t i)() if (i < arrays.length) { import std.random: uniform; return &arrays[i][uniform(0, $)]; } import std.stdio: writeln; import std.meta: staticMap, aliasSeqOf; import std.range: iota; writeln(staticMap!(randomElemAddr, aliasSeqOf!(iota(arrays.length)))); } void main() { int[] a = [1]; int[] b = [2, 3]; double[] c = [4, 5, 6]; printRandomElemAddr(a); printRandomElemAddr(a, b); printRandomElemAddr(a, b, c); } |
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Saturday, 12 September 2020 at 14:31:59 UTC, Paul Backus wrote:
> On Saturday, 12 September 2020 at 03:19:23 UTC, mw wrote:
>> I.e. I want to learn the generic meta-programming way to assemble such parameter list (&(x[i], &(y[j])) at compile time, it is possible?
>
> It's possible if you use a helper function. Here's how:
>
> import std.meta: allSatisfy;
> import std.traits: isArray;
>
> void printRandomElemAddr(Arrays...)(Arrays arrays)
> if (allSatisfy!(isArray, Arrays))
> {
> auto randomElemAddr(size_t i)()
> if (i < arrays.length)
> {
> import std.random: uniform;
>
> return &arrays[i][uniform(0, $)];
> }
>
> import std.stdio: writeln;
> import std.meta: staticMap, aliasSeqOf;
> import std.range: iota;
>
> writeln(staticMap!(randomElemAddr, aliasSeqOf!(iota(arrays.length))));
> }
>
> void main()
> {
> int[] a = [1];
> int[] b = [2, 3];
> double[] c = [4, 5, 6];
>
> printRandomElemAddr(a);
> printRandomElemAddr(a, b);
> printRandomElemAddr(a, b, c);
> }
Thanks, this works. staticMap and aliasSeqOf is the key.
Now, let me expand this challenge: suppose we need to add a new set of variable length extra parameters in parallel to the arrays, i.e:
// just use scalar type for demo
int extraA;
string extraB;
double extraC;
// need to be called as:
printRandomElemAddr(extraA, a);
printRandomElemAddr(extraA, extraB, a, b);
printRandomElemAddr(extraA, extraB, extraC, a, b, c);
basically, two sets of variadic parameters, but need to be treated differently:
-- the 1st scalar set, just use as it is
-- the 2nd array set, need some processing (which you have done).
Now the question is how to pass & handle 2 sets of variadic parameters?
|
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 12 September 2020 at 18:16:51 UTC, mw wrote:
> Now, let me expand this challenge: suppose we need to add a new set of variable length extra parameters in parallel to the arrays, i.e:
>
> [...]
>
> Now the question is how to pass & handle 2 sets of variadic parameters?
void fun(Args...)(Args args)
if (args.length % 2 == 0)
{
alias firstSet = args[0 .. $/2];
alias secondSet = args[$/2 .. $];
// rest of function body goes here
}
You will probably also want to include some `static asserts` to make sure each set contains arguments of the appropriate types.
|
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Saturday, 12 September 2020 at 19:06:47 UTC, Paul Backus wrote: > On Saturday, 12 September 2020 at 18:16:51 UTC, mw wrote: >> Now, let me expand this challenge: suppose we need to add a new set of variable length extra parameters in parallel to the arrays, i.e: >> >> [...] >> >> Now the question is how to pass & handle 2 sets of variadic parameters? > > alias firstSet = args[0 .. $/2]; > alias secondSet = args[$/2 .. $]; This solution assumes the two sets are of equal size; what if we don't have such assumption? i.e. we only know the two sets divided into two logical groups. I've tried something like this: the AliasSeq specify the logical divide printRandomElemAddr(AliasSeq!(extraA, extraB, extraC, extraD), a, b, c); but cannot make it work. (I'm asking for a more general solution, e.g. what if we have 3, or N sets of variadic parameters?) Looks like we can only pass 1 variadic parameters, then the question is what's the best way to divide it? Is there any special marker (variable or type?) can be used to divide? and what's the staticSplit? |
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Saturday, 12 September 2020 at 19:31:57 UTC, mw wrote:
>
> (I'm asking for a more general solution, e.g. what if we have 3, or N sets of variadic parameters?)
>
>
> Looks like we can only pass 1 variadic parameters, then the question is what's the best way to divide it?
>
> Is there any special marker (variable or type?) can be used to divide? and what's the staticSplit?
It's possible, but there's no widely-used technique, because it's much easier to simply pass each "parameter set" as a separate array or tuple. So your function signature would look like:
auto fun(Set1, Set2, Set3)(Set1 args1, Set2 args2, Set3 args3)
if (allSatisfy!(Or!(isArray, isTuple), Set1, Set2, Set3))
Or in the variadic case:
auto fun(Args...)(Args args)
if (allSatisfy!(Or!(isArray, isTuple), Args))
If you have a "real-life" application in mind for this, I'd be curious to hear what it is.
|
September 13, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Saturday, 12 September 2020 at 20:29:40 UTC, Paul Backus wrote:
> On Saturday, 12 September 2020 at 19:31:57 UTC, mw wrote:
>>
>> (I'm asking for a more general solution, e.g. what if we have 3, or N sets of variadic parameters?)
>>
>>
>> Looks like we can only pass 1 variadic parameters, then the question is what's the best way to divide it?
>>
>> Is there any special marker (variable or type?) can be used to divide? and what's the staticSplit?
>
> It's possible, but there's no widely-used technique, because it's much easier to simply pass each "parameter set" as a separate array or tuple. So your function signature would look like:
>
> auto fun(Set1, Set2, Set3)(Set1 args1, Set2 args2, Set3 args3)
> if (allSatisfy!(Or!(isArray, isTuple), Set1, Set2, Set3))
>
> Or in the variadic case:
>
> auto fun(Args...)(Args args)
> if (allSatisfy!(Or!(isArray, isTuple), Args))
>
> If you have a "real-life" application in mind for this, I'd be curious to hear what it is.
I'm wrapping a C library, trying to write a single D function / template that can work with a group of C functions, hence I need that kind of signature I described.
I'll post the code when I'm ready.
|
September 12, 2020 Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays? | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Sat, Sep 12, 2020 at 07:31:57PM +0000, mw via Digitalmars-d-learn wrote: [...] > I've tried something like this: the AliasSeq specify the logical divide > > printRandomElemAddr(AliasSeq!(extraA, extraB, extraC, extraD), a, b, c); > > but cannot make it work. Yes, because AliasSeq auto-expands, so `func(AliasSeq!(A,B,C), AliasSeq!(D,E,F))` is equivalent to `func(A,B,C,D,E,F)`. > (I'm asking for a more general solution, e.g. what if we have 3, or N > sets of variadic parameters?) > > Looks like we can only pass 1 variadic parameters, then the question is what's the best way to divide it? > > Is there any special marker (variable or type?) can be used to divide? > and what's the staticSplit? Maybe the nested templates hack could be used? It depends on what exactly you're trying to do though: template myFunc(Args1...) { template myFunc(Args2...) { auto myFunc(/* runtime params here */) { // you can use Args1.length and // Args2.length here. ... } } } myFunc!(A,B,C)!(D,E,F)(/* runtime args here */); Alternatively, define a non-eponymous version of AliasSeq that will allow you to pass multiple lists of compile-time parameters without auto-expanding and coalescing them: template WrappedSeq(T...) { // N.B.: not eponymous alias members = T; } auto myFunc(Args1, Args2)(/*runtime params*/) { alias list1 = Args1.members; // need manual unwrap alias list2 = Args2.members; } // (Yeah the caller side will look ugly. C'est la vie.) myFunc!(WrappedSeq!(A,B,C), WrappedSeq!(D,E,F))(/*runtime args*/); T -- Why can't you just be a nonconformist like everyone else? -- YHL |
Copyright © 1999-2021 by the D Language Foundation