digitalmars.D.learn - Transforming an argument list
- Jean-Louis Leroy (64/64) Jun 20 2017 Another meta-programming question ;-)
- ag0aep6g (39/40) Jun 20 2017 1) You can foreach over args:
Another meta-programming question ;-) Inside a variadic function template that takes a list of arguments, I want to call another function and pass it the arguments run through another function. In C++ it would look like this: template<typename T> T double_int(T val) { return val; } int double_int(int val) { return 2 * val; } template<typename... T> void double_ints(void F(T...), T... args) { F(double_int(args)...); } void test(const char* str, int val) { cout << str << " = " << val << "\n"; } int main() { double_ints(test, "1 + 2", 3); // 1 + 2 = 6 return 0; } I tried this in D: void test(string name, int val) { writefln("%s = %d", name, val); } template DoubleInt(A...) { static if (A.length == 0) alias DoubleInt = AliasSeq!(); else static if (is(typeof(A[0]) == int)) alias DoubleInt = AliasSeq!(2 * A[0], DoubleInt!(A[1..$])); else alias DoubleInt = AliasSeq!(A[0], DoubleInt!(A[1..$])); } void double_ints(F, A...)(F f, A args) { f(DoubleInt!args); } void main() { double_ints(&test, "1 + 2", 3); } ...but ldc2 complains that "variable __args_field_1 cannot be read at compile time". Yeah, I understand... I also tried a solution similar to C++: A DoubleInt(A)(A a) if (!is(typeof(A) == int)) { return a; } A DoubleInt(A)(A a) if (is(typeof(A) == int)) { return 2 * a; } void double_ints(F, A...)(F f, A args) { f(DoubleInt!(args)); } ...but I get: "template instance callas.double_ints!(void function(string, int), string, int) error instantiating". The difference with C++ is that I don't get to control the expansion of the argument pack: "f(DoubleInt!(args))" is interpreted as "f(DoubleInt!(args...))", not "f(DoubleInt!(args))...". Any ideas? Thanks...
Jun 20 2017
On 06/20/2017 10:28 PM, Jean-Louis Leroy wrote:Any ideas? Thanks...1) You can foreach over args: ---- void test(string name, int val) { import std.stdio; writefln("%s = %d", name, val); } T double_int(T)(T val) { return val; } int double_int(int val) { return 2 * val; } void double_ints(F, A...)(F f, A args) { foreach (ref arg; args) arg = double_int(arg); f(args); } void main() { double_ints(&test, "1 + 2", 3); } ---- 2) Or you could make a generic `tuple_map` function and use that: ---- /* ... test, double_int, and main as above ... */ auto tuple_map(alias fun, T ...)(T things) { import std.typecons: Tuple, tuple; static if (things.length == 0) return tuple(); else { auto head = fun(things[0]); auto tail = tuple_map!fun(things[1 .. $]); return tuple(head, tail.expand); } } void double_ints(F, A...)(F f, A args) { f(tuple_map!double_int(args).expand); } ----
Jun 20 2017