www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Variadic template with template arguments in pairs

reply Anonymouse <asdf asdf.net> writes:
I'm trying to create a variadic template function that takes 
pairs of arguments. Sort of like getopt, I want to pass any 
number of pairs of a string and some pointer. Or any size chunk 
larger than one.

Something like the following, assuming the existence of a 
hypothetical template pairwise:

---

void doByPair(Args...)(Args args)
if (Args.length)
{
     foreach (pair; args.pairwise)
     {
         static assert(is(typeof(pair[0]) == string));
         static assert(isPointer!(pair[1]));
         assert(pair[1] !is null);

         string desc = pair[0];
         auto value = *pair[1];
         writefln("%s %s: %s", typeof(value).stringof, desc, 
value);
     }
}

bool b1 = true;
bool b2 = false;
string s = "some string";
int i = 42;

doByPair("foo", &b1, "bar", &b2, "baz", &s, "qux", &i);

---

Should output:

bool foo: true
bool bar: false
string baz: some string
int qux: 42

What is the right way to go about doing this?
Sep 12 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 12 September 2018 at 15:12:16 UTC, Anonymouse wrote:
 void doByPair(Args...)(Args args)
 if (Args.length)
 {
     foreach (pair; args.pairwise)
     {
         static assert(is(typeof(pair[0]) == string));
         static assert(isPointer!(pair[1]));
         assert(pair[1] !is null);

         string desc = pair[0];
         auto value = *pair[1];
         writefln("%s %s: %s", typeof(value).stringof, desc, 
 value);
     }
 }
The easiest way is probably to iterate using indices with an increment of 2, e.g.: static foreach(i; iota(0, args.length, 2)) { static assert(is(typeof(args[i]) == string)); static assert(isPointer!(args[i+1])); // etc. } Another alternative is to write the function recursively: void doByPair(T, Rest...)(string desc, T* valuePtr, Rest rest) { writefln("%s %s: %s", T.stringof, desc, *valuePtr); if (rest.length) doByPair(rest); }
Sep 12 2018
parent Anonymouse <asdf asdf.net> writes:
On Wednesday, 12 September 2018 at 21:33:17 UTC, Paul Backus 
wrote:
 Another alternative is to write the function recursively:

 void doByPair(T, Rest...)(string desc, T* valuePtr, Rest rest)
 {
     writefln("%s %s: %s", T.stringof, desc, *valuePtr);
     if (rest.length) doByPair(rest);
 }
Rest... is genius, I don't know why it never struck me before. My current solution doesn't support having chunks of varying sizes (ideally it would take 2 *or* 3), but the current use case is okay with just pairs for now. I imagine I could keep the same signature and just access a third argument with rest[0] and recursing on rest[1..$]. Many thanks!
Sep 15 2018