www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - staticMap but with two arguments

reply John Chapman <john.chapman live.com> writes:
I have two AliasSeqs: one containing a function's parameters 
(SourceSeq), the other containing the types I want to convert 
said parameters to (TargetSeq). I'd use something like staticMap 
to call the conversion function with both a parameter from 
SourceSeq and a type from TargetSeq, and return an AliasSeq of 
converted values which will be forwarded to another function. 
staticMap's "fun" can only be instantiated with a single 
argument, while I need it to work with two.

E.g.:
```
template toTarget(alias source, Target) {
   static if (is(typeof(source) == int) && is(Target == string)) 
// for example, convert int to string
}

alias TargetSeq = Parameters!targetFunc;

auto wrapperFunc(A...)(A) {
   alias SourceSeq = __traits(parameters);
   return targetFunc(staticMap!(toTarget, SourceSeq)); // How 
would I call staticMap (or something similar) with SourceSeq 
*and* TargetSeq?
}
```

I could build the list of converted values manually but I wanted 
something smart (like staticMap) to do it inline. I thought 
ApplyLeft/Right could help but couldn't get my head around it.
Feb 05 2023
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 2/5/23 17:20, John Chapman wrote:

 staticMap's "fun" can only be
 instantiated with a single argument, while I need it to work with two.
I adapted staticMap's implementation to two sets of arguments: import std.meta : AliasSeq; // The first half of 'args' is the "first arguments" and // the second half is the "second arguments". // // (This can be generalized to N sets of arguments.) template staticMap2(alias fun, args...) { alias firsts = args[0 .. $ / 2]; alias seconds = args[$ / 2 .. $]; static assert(firsts.length == seconds.length, "Mismatched number of first and second arguments"); alias staticMap2 = AliasSeq!(); static foreach (i; 0 .. firsts.length) { staticMap2 = AliasSeq!(staticMap2, fun!(firsts[i], seconds[i])); } } // An example struct with two template parameters struct S(T, size_t length) { } // An example template that creates instantiations of the S template // (This can be generalized to instantiation of any template.) template Instantiate(T, size_t length) { alias Instantiate = S!(T, length); } // An example use alias myTypes = AliasSeq!(int, double, long); alias mySizes = AliasSeq!(1, 2, 3); alias result = staticMap2!(Instantiate, myTypes, mySizes); pragma(msg, result); void main() { } Ali
Feb 06 2023
parent reply John Chapman <john.chapman live.com> writes:
On Monday, 6 February 2023 at 09:17:07 UTC, Ali Çehreli wrote:
 I adapted staticMap's implementation to two sets of arguments:
Thanks Ali, that's perfect. I thought of splitting the args in half a few hours later but hadn't got around to trying it.
Feb 06 2023
parent reply John Chapman <john.chapman live.com> writes:
On Monday, 6 February 2023 at 09:17:07 UTC, Ali Çehreli wrote:
 I adapted staticMap's implementation to two sets of arguments:
So I've got this implementation, but wonder if I can generalise the arg splitting portion rather than write it manually for each N? ```d template staticMapN(size_t N, alias fun, args...) if (args.length % N == 0) { alias staticMapN = AliasSeq!(); static foreach (i; 0 .. args.length / N) static if (N == 1) staticMapN = AliasSeq!(staticMapN, fun!(args)); else static if (N == 2) staticMapN = AliasSeq!(staticMapN, fun!(args[0 .. $ / N][i], args[$ / N .. ($ / N) * 2][i])); else static if (N == 3) staticMapN = AliasSeq!(staticMapN, fun!(args[0 .. $ / N][i], args[$ / N .. ($ / N) * 2][i], args[($ / N) * 2 .. ($ / N) * 3][i])); // etc } ```
Feb 08 2023
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 2/8/23 12:04, John Chapman wrote:

 rather than write it manually for each N?
import std.meta : AliasSeq; template pickArgs(size_t totalElements, size_t argsPerElement, size_t whichElement, args...) { alias pickArgs = AliasSeq!(); static foreach (a; 0 .. argsPerElement) { pickArgs = AliasSeq!(pickArgs, args[whichElement + a * totalElements]); } } template staticMapN(size_t N, alias fun, args...) { static assert(N != 0, "N must be non-zero."); static assert((args.length % N) == 0, "Mismatched number of arguments"); enum totalElements = args.length / N; alias staticMapN = AliasSeq!(); static foreach (e; 0 .. totalElements) { staticMapN = AliasSeq!(staticMapN, fun!(pickArgs!(totalElements, N, e, args))); } } // An example struct with some template parameters struct S(T, size_t length, size_t foo, size_t bar) { } // An example template that creates instantiations of the S template template Instantiate(T, size_t length, size_t foo, size_t bar) { alias Instantiate = S!(T, length, foo, bar); } // Compile-time argument sets for three instantiations of the S template alias myTypes = AliasSeq!(int, double, long); alias mySizes = AliasSeq!(1, 2, 3); alias myFoos = AliasSeq!(42, 43, 44); alias myBars = AliasSeq!(100, 200, 300); // A test with those 4 sets of template arguments alias result = staticMapN!(4, Instantiate, myTypes, mySizes, myFoos, myBars); pragma(msg, result); void main() { } I could not figure out eliminating the hard-coded 4. Can we introspect the parameter list of a template like 'fun' in the example? If we could, then we could get 4 that way. Ali
Feb 09 2023
parent reply John Chapman <john.chapman live.com> writes:
On Thursday, 9 February 2023 at 19:17:55 UTC, Ali Çehreli wrote:
 I could not figure out eliminating the hard-coded 4. Can we 
 introspect the parameter list of a template like 'fun' in the 
 example? If we could, then we could get 4 that way.
Thank you for this. I don't mind hard-coding the N argument. TemplateArgsOf needs an instantiated template but maybe ```enum N = count(fun.stringof, ',') + 1``` is good enough.
Feb 09 2023
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 2/9/23 12:45, John Chapman wrote:
 On Thursday, 9 February 2023 at 19:17:55 UTC, Ali Çehreli wrote:
 I could not figure out eliminating the hard-coded 4. Can we introspect
 the parameter list of a template like 'fun' in the example? If we
 could, then we could get 4 that way.
Thank you for this. I don't mind hard-coding the N argument. TemplateArgsOf needs an instantiated template but maybe ```enum N = count(fun.stringof, ',') + 1``` is good enough.
Hopefully but very fragile: template t(int[] T = [ 1, 2 ]) {} void main() { import std.algorithm : count; enum N = count(t.stringof, ',') + 1; static assert(N == 1); // FAILS } Same thing with any other thing with comma in it e.g. template t(T = anotherTemplate!(1, 2)) {} Ali
Feb 09 2023