module autoRefTuple; import std.range; import std.traits; import std.typetuple; import std.conv; template hasLvalueElements( R ) if ( isInputRange!R ) { enum hasLvalueElements = is( typeof( { R r; auto a = &( r.front ); } ) ); } template hasLvalueElements( R ) if ( !isInputRange!R ) { pragma( msg, R ); static assert( false ); } struct Ref( T ) { static struct RefImpl { T* _data; @property ref T data( ) { return *_data; } alias data this; ref T opAssign( ref T value ) { _data = &value; return *_data; } void assign( ref T value ) { _data = &value; } } private RefImpl Ref; alias Ref this; ref T opAssign( T value ) { *Ref._data = value; return *Ref._data; } } struct NoRef( T ) { static struct RefImpl { T data; alias data this; ref T opAssign( T value ) { data = value; return data; } } private RefImpl Ref; ref T _data( ) { return Ref.data; } alias _data this; ref T opAssign( T value ) { Ref.data = value; return Ref.data; } } template autoRefElementType( R ) { alias Select!( hasLvalueElements!R, Ref!( ElementType!( R ) ), NoRef!( ElementType!( R ) ) ) autoRefElementType; } struct AutoRefTuple( T... ) { alias TypeTuple!( staticMap!( autoRefElementType, T ) ) PT; PT field; alias field expand; this( T values ) { foreach ( i, val; values ) { field[i].Ref = val.front; } } string toString( ) { string result = AutoRefTuple.stringof ~ "("; foreach ( i, field; expand ) { result ~= to!string( field.Ref.data ) ~ ","; } return result[0..$-1] ~ ")"; } } auto autoRefTuple( R... )( R ranges ) { return AutoRefTuple!R( ranges ); }