template / function arguments to apply to fun
An alias to fun(args) or fun!(args)
apply can call regular functions with arguments known either at compile-time, or run-time:
int add(int a, int b) { return a + b; } enum int a = 2, b = 3; enum int sum = apply!(add, a, b); static assert(sum == 5); int x = 2, y = 5; int z = apply!((a, b) => a + b, x, y); assert(z == 7); // TODO: Show higher-order template example // When `apply` is used to call functions it returns the result // by reference (when possible): static struct S { int x; } static ref int getX(ref S s) { return s.x; } static int inc(ref int x) { return ++x; } auto s = S(41); int theAnswer = apply!(inc, apply!(getX, s)); assert (theAnswer == 42); assert (s.x == 42);
apply can also instantiate function templates with compile-time parameters and alias or call them:
int mul(int a, int b)() { return a * b; } enum product = apply!(mul, 2, 7); static assert (product == 14); static int counter = 0; int offset(int x) { return 10 * ++counter + x; } alias offset7 = apply!(offset, 7); assert(offset7() == 17); assert(apply!(offset, 7) == 27); assert(offset7() == 37);
apply can instnatiate manifest constant (a.k.a. enum) templates:
enum ulong square(uint x) = x * x; enum result = apply!(square, 3); static assert(result == 9);
Two or more apply instances can be chained to provide the template and later the run-time arguments of a function template:
static T[] transform(alias fun, T)(T[] arr) { foreach (ref e; arr) e = fun(e); return arr; } alias result = apply!( apply!(transform, x => x * x, int), [2, 3, 4, 5]); static assert (result == [4, 9, 16, 25]);
apply can instnatiate alias templates
alias ArrayOf(T) = T[]; alias ArrayType = apply!(ArrayOf, int); static assert (is(ArrayType == int[])); import std.traits : CommonType; alias Types = AliasSeq!(byte, short, int, long); static assert (is(apply!(CommonType, Types) == long));
apply can instnatiate higher-order templates that yield alias sequences:
1 import std.meta : staticMap; 2 3 alias ArrayOf(T) = T[]; 4 alias Types = AliasSeq!(byte, short, int, long); 5 alias ArrayTypes = apply!(staticMap, ArrayOf, Types); 6 static assert (is(ArrayTypes == AliasSeq!(byte[], short[], int[], long[]))); 7 8 template Overloads(T, string member) 9 { 10 alias Overloads = AliasSeq!(__traits(getOverloads, T, member)); 11 } 12 13 struct S 14 { 15 static int use(int x) { return x + 1; } 16 static bool use(char c) { return c >= '0' && c <= '9'; } 17 static char use(string s) { return s[0]; } 18 } 19 20 static assert(apply!(Overloads, S, "use").length == 3); 21 22 alias atIndex(size_t idx, List...) = Alias!(List[idx]); 23 24 static assert( 25 apply!( // 3) call the function with the argument `10` 26 apply!( // 2) get the first element (with type `int use(int x)`) 27 atIndex, 28 0, 29 apply!(Overloads, S, "use") // 1) get the `use` overload set 30 ), 31 10 32 ) == 11); 33 34 static assert( 35 apply!(apply!(atIndex, 1, apply!(Overloads, S, "use")), '3') == true); 36 37 alias useOverloadSet = Alias!(__traits(getOverloads, S, "use"))[0]; 38 alias useOverloadSet = Alias!(__traits(getOverloads, S, "use"))[1]; 39 alias useOverloadSet = Alias!(__traits(getOverloads, S, "use"))[2]; 40 41 static assert(useOverloadSet(41) == 42); 42 //static assert(useOverloadSet('@') == false); 43 //static assert(useOverloadSet('7') == true); 44 static assert(useOverloadSet("Voldemort") == 'V'); 45 46 template AliasTuple(T...) 47 { 48 alias expand = T; 49 } 50 51 template applyN(alias fun, Tuples...) 52 if (Tuples.length > 0) 53 { 54 static if (Tuples.length == 1) 55 alias applyN = apply!(fun, Tuples[0].expand); 56 else 57 alias applyN = applyN!( 58 apply!(fun, Tuples[0].expand), 59 Tuples[1 .. $]); 60 } 61 62 //alias AT = AliasTuple; 63 //applyN!(Overloads, AT!(S, "use"), atIndex, 2, "asd"); 64 //applyN!("use", ApplyLeft!(Overloads, S), ApplyLeft!(atIndex, 2) 65 66 static assert( 67 apply!(apply!(atIndex, 2, apply!(Overloads, S, "use")), "asd") == 'a');
Applies the sequence of arguments args to the function or template fun either as function or template arguments, at compile-time or at run-time (if CTFE is not possible).
apply is most likely to be found used as a building block in higher-order templates and AliasSeq algorithms like staticMap which need to call or instantiate (as appropriate) functions or templates, passed as parameters.