On 06/17/13 14:57, TommiT wrote: > On Monday, 17 June 2013 at 12:21:31 UTC, Artur Skawina wrote: >> >> A more correct, but a bit less readable version (the types of 'values' and >> 'arr' >> elements do not have to match) would be: >> >> void bar(T...)(T values) { >> static if (T.length) { >> NTup!(T.length, typeof(arr[T[0].init])) tmp; >> foreach (i, ref v; values) >> tmp[i] = arr[v]*10; >> foo(tmp); >> } >> else >> foo(); >> } >> >> template NTup(size_t N, T...) { >> static if (N>1) >> alias NTup = NTup!(N-1, T, T[$-1]); >> else >> alias NTup = T; >> } > > Argh, that's a lot of boilerplate. Thanks for pointing this out. I didn't > notice in your previous example that the expression types had to match with > the parameter types. Now I really do think that we need the C++ ellipsis > notation (it's just the ellipsis can be omitted when it would be right next > to the tuple): > > void bar(T...)(T values) > { > foo((arr[values] * 10)...); > } >
Well, the only real difference between these two examples is s/T tmp/NTup!(T.length, typeof(arr[T[0].init])) tmp/ 'NTup' would be a lib thing, and the empty-args case would have to handled (or disallowed) in real code anyway. So it's not /that/ much more boilerplate. Another solution would be to have the following hidden in some lib: struct _ForEach(alias MAP, TS...) { NTup!(TS.length, typeof(MAP(TS[0].init))) tuple; this(TS values) { foreach (i, ref v; values) tuple[i] = MAP(v); } } auto ForEach(alias MAP, TS...)(TS ts) { return _ForEach!(MAP, TS)(ts); } Then 'bar' becomes just: void bar(T...)(T values) { foo(ForEach!(a=>arr[a]*10)(values).tuple); } Yes, this is not as concise as '...' would be. But, with a bit more tuple support in the language, the '.tuple' part wouldn't be necessary, and then it's just foo(ForEach!(a=>arr[a]*10)(values)); vs foo((arr[values] * 10)...); artur