July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Strakhov | On Saturday, 6 July 2013 at 12:21:29 UTC, Max Strakhov wrote: > Artur, if i use your solution like > > printf("...", ForEach!(val => conv(val).c_str())(values).tuple); > > Than i would get a crash, because all the tuple elements would be char*'s, pointing to already freed memory, as std::string's destructor gets called each time right after alias function exits. Ths is what c++ unpacking operator for: i actually return a packed list of std::string's, apply .c_str() to each and than unpack the list to current context. I thought about this a bit more and realised you're right. The following should work though: printf( "...", ForEach!(tmp => tmp.c_str())(ForEach!(val => conv(val))(values).tuple).tuple ); It's a defect in ForEach though, and gives me more reason to ask for the C++ style ellipsis expansion operator for D. |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | > The following should work though: > > printf( "...", ForEach!(tmp => tmp.c_str())(ForEach!(val => conv(val))(values).tuple).tuple ); I had the same idea too, but couldn't make it work: compiler complains about failed CTFE or something. On the other hand i might do somethong wrong. > It's a defect in ForEach though, and gives me more reason to ask for the C++ style ellipsis expansion operator for D. Yeap, i personally find (as * 2)... awesome feature of c++. |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Strakhov | On Saturday, 6 July 2013 at 17:29:36 UTC, Max Strakhov wrote: >> The following should work though: >> >> printf( "...", ForEach!(tmp => tmp.c_str())(ForEach!(val => conv(val))(values).tuple).tuple ); > > I had the same idea too, but couldn't make it work: compiler complains about failed CTFE or something. On the other hand i might do somethong wrong. There were a couple of typos in _TypeMap. That's a correct one: template _TypeMap(alias MAP, size_t N, TS...) { static if (N<TS.length) alias _TypeMap = _TypeMap!(MAP, N+1, TS[0..N], typeof(MAP(TS[N].init)), TS[N+1..$]); else alias _TypeMap = TS; } > Yeap, i personally find (as * 2)... awesome feature of c++. Me too. |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Saturday, 6 July 2013 at 15:23:40 UTC, Artur Skawina wrote:
> On 07/06/13 14:21, Max Strakhov wrote:
>> Artur, if i use your solution like
>>
>> printf("...", ForEach!(val => conv(val).c_str())(values).tuple);
>>
>> Than i would get a crash, because all the tuple elements would be char*'s, pointing to already freed memory, as std::string's destructor gets called each time right after alias function exits. Ths is what c++ unpacking operator for: i actually return a packed list of std::string's, apply .c_str() to each and than unpack the list to current context.
>
> Can you show some simple code that exhibits the problem?
>
> artur
import std.stdio;
template _TypeMap(alias MAP, size_t N, TS...) {
static if (N<TS.length)
alias _TypeMap = _TypeMap!(MAP,
N+1,
TS[0..N],
typeof(MAP(TS[N].init)),
TS[N+1..$]);
else
alias _TypeMap = TS;
}
template TypeMap(alias MAP, TS...) {
alias TypeMap = _TypeMap!(MAP, 0, TS);
}
struct _ForEach(alias MAP, TS...)
{
TypeMap!(MAP, TS) 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);
}
int[2] getArray(int n)
{
int[2] data = n;
return data;
}
void foo(R...)(R ranges)
{
foreach (range; ranges)
foreach (value; range)
write(value, " ");
}
void main()
{
// Expecting this to print: 1 1 2 2 3 3
foo(ForEach!(a => getArray(a)[])(1, 2, 3).tuple);
// ... but it prints random garbage
}
Notice that there were a couple of typos in _TypeMap.
|
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | > There were a couple of typos in _TypeMap.
Yeah, i fixed them myself. Still, there were some problems.
I like my solution better anyway, because it behaves exactly like c++ ... operator and just expands some code for all items in tuple.
|
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Saturday, 6 July 2013 at 15:23:40 UTC, Artur Skawina wrote: > ... Can you tell me why this isn't working though? import std.stdio, std.typetuple; template _TypeMap(alias MAP, size_t N, TS...) { static if (N<TS.length) alias _TypeMap = _TypeMap!(MAP, N+1, TS[0..N], typeof(MAP(TS[N].init)), TS[N+1..$]); else alias _TypeMap = TS; } template TypeMap(alias MAP, TS...) { alias TypeMap = _TypeMap!(MAP, 0, TS); } struct _ForEach(alias MAP, TS...) { TypeMap!(MAP, TS) tuple; this(TS values) { foreach (i, v; values) tuple[i] = MAP(v); } } auto ForEach(alias MAP, TS...)(TS ts) { return _ForEach!(MAP, TS)(ts); } int[2] getArray(int n) { int[2] data = n; return data; } void foo(R...)(R ranges) { foreach (range; ranges) foreach (value; range) write(value, " "); } void main() { alias pack = TypeTuple!(1, 2, 3); // prints random garbage foo(ForEach!(tmp => tmp[]) (ForEach!(a => getArray(a))(pack).tuple).tuple); } |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | On 07/06/13 19:42, TommiT wrote: > TS[N+1..$]); > Notice that there were a couple of typos in _TypeMap. Thanks for catching that. > int[2] getArray(int n) > { > int[2] data = n; > return data; > } > > void foo(R...)(R ranges) > { > foreach (range; ranges) > foreach (value; range) > write(value, " "); > } > > void main() > { > // Expecting this to print: 1 1 2 2 3 3 > foo(ForEach!(a => getArray(a)[])(1, 2, 3).tuple); > // ... but it prints random garbage > } This is slicing a local static array and returning that slice, which points to the stack and lives only until the lambda returns. Moving the data to the heap or simply returning it directly (ie by value) will work: > foo(ForEach!(a => getArray(a).dup[])(1, 2, 3).tuple); > foo(ForEach!(a => getArray(a))(1, 2, 3).tuple); I like Max's solution better than mine too, btw. Why didn't i think of that... :) artur |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | On Saturday, 6 July 2013 at 18:17:34 UTC, TommiT wrote: > Can you tell me why this isn't working though? I can get this so far that it prints: 1 1 2 0 <random> <random> import std.stdio, std.typetuple; template _TypeMap(alias MAP, size_t N, TS...) { static if (N<TS.length) alias _TypeMap = _TypeMap!(MAP, N+1, TS[0..N], typeof(MAP([TS[N]][0])), TS[N+1..$]); else alias _TypeMap = TS; } template TypeMap(alias MAP, TS...) { alias TypeMap = _TypeMap!(MAP, 0, TS); } struct _ForEach(alias MAP, TS...) { TypeMap!(MAP, TS) tuple; this(TS values) { foreach (i, v; values) tuple[i] = MAP(v); } } auto ForEach(alias MAP, TS...)(TS ts) { return _ForEach!(MAP, TS)(ts); } int[2] getArray(int n) { int[2] data = n; return data; } void foo(R...)(R ranges) { foreach (range; ranges) foreach (value; range) write(value, " "); } void main() { alias pack = TypeTuple!(1, 2, 3); // prints random garbage foo(ForEach!((ref int[2] tmp) { return tmp[]; }) (ForEach!(a => getArray(a))(pack).tuple).tuple); } |
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Saturday, 6 July 2013 at 18:26:28 UTC, Artur Skawina wrote:
> This is slicing a local static array and returning that slice,
> which points to the stack and lives only until the lambda
> returns.
Yes, but certainly simple parameter pack expansion shouldn't be this brittle. I want to be able to write:
foo(getArray(v)[]...); // v is a parameter pack (1, 2, 3)
And be confident in that it gets simply re-written as:
foo(getArray(v[0])[], getArray(v[1])[], getArray(v[2])[]);
It's easy to conceptualise and easy to get it right.
|
July 06, 2013 Re: Variadic template arguments unpacking | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | > foo(getArray(v[0])[], getArray(v[1])[], getArray(v[2])[]); > > It's easy to conceptualise and easy to get it right. I wrote a template, that can do something like that: template Expand(string code, string Args, string args, Ts...) { const hasType = std.string.indexOf(code, "%Arg") != -1; const hasVal = std.string.indexOf(code, "%arg") != -1; static if(hasType) const code1 = std.array.replace(code, "%Arg", Args ~ "[%d]"); else const code1 = code; static if(hasVal) const code2 = std.array.replace(code1, "%arg", args ~ "[%d]"); else const code2 = code1; template Fun(size_t i, T) { static if(!hasType && !hasVal) alias Fun = TypeTuple!(code2); else static if(hasType && hasVal) alias Fun = TypeTuple!(std.string.format(code2, i, i)); else alias Fun = TypeTuple!(std.string.format(code2, i)); } template ConcatArgs() { const Val = ""; } template ConcatArgs(T, As...) if(!is(T == string)) { static assert(T); } template ConcatArgs(string s, As...) if(As.length == 0) { const Val = s; } template ConcatArgs(string s, As...) if(As.length != 0) { const Val = s ~ ", " ~ ConcatArgs!As.Val; } const Val = ConcatArgs!(staticIndexedMap!(Fun, Ts)).Val; } Usage: writeln(Expand!("getArray(%arg)[]", "", "v", string, int, int).Val); // == getArray(v[0])[], getArray(v[1])[], getArray(v[2])[] If anyine has any ideas how make this implementation simplier, bring it on :) |
Copyright © 1999-2021 by the D Language Foundation