digitalmars.D.learn - staticMap but with two arguments
- John Chapman (25/25) Feb 05 2023 I have two AliasSeqs: one containing a function's parameters
- =?UTF-8?Q?Ali_=c3=87ehreli?= (34/36) Feb 06 2023 I adapted staticMap's implementation to two sets of arguments:
- John Chapman (3/4) Feb 06 2023 Thanks Ali, that's perfect. I thought of splitting the args in
- John Chapman (21/22) Feb 08 2023 So I've got this implementation, but wonder if I can generalise
- =?UTF-8?Q?Ali_=c3=87ehreli?= (46/47) Feb 09 2023 import std.meta : AliasSeq;
- John Chapman (4/7) Feb 09 2023 Thank you for this. I don't mind hard-coding the N argument.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/18) Feb 09 2023 Hopefully but very fragile:
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
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
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
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
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
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
On 2/9/23 12:45, John Chapman wrote:On Thursday, 9 February 2023 at 19:17:55 UTC, Ali Çehreli wrote: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)) {} AliI 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