Simen Kjaeraas
| On 2012-11-05, 15:53, Joseph Rushton Wakeling wrote:
> Hello all,
>
> Suppose I want to define a tuple type which may have a variable length, e.g.:
>
> template Tup(ID, Properties...)
> {
> static if(Properties.length == 0)
> alias Tuple!(ID, "id") Tup;
> else
> alias Tuple!(ID, "id", Properties) Tup;
> }
>
> Now, it's trivial to include an arbitrary selection of named values in this, e.g.
>
> auto t1 = Tup!(size_t, real, "value")(3, 4.5);
> writeln(t1);
> writeln(t1.id, " ", t1.value);
>
> auto t2 = Tup!(size_t, real, "value", bool, "active")(3, 4.5, true);
> writeln(t2);
> writeln(t2.id, " ", t2.value, " ", t2.active);
>
> However, suppose now I want to define a container struct which holds an array of
> tuples of the specified type. Here's what I came up with:
>
> struct Container(ID, Properties...)
> {
> Tup!(ID, Properties)[] contents;
>
> void add(ID i, Properties p)
> {
> static if(Properties.length == 0)
> contents ~= Tup!(ID)(i);
> else
> contents ~= Tup!(ID, Properties)(i, p);
> }
> }
>
> Now, if I make properties empty, this works just fine:
>
> auto c1 = Container!(size_t)();
> c1.add(3);
> c1.add(7);
> c1.add(2);
> writeln(c1);
> foreach(t, tup; c1.contents)
> writeln("[", t, "] ", tup.id);
> writeln();
>
> ... and likewise if I pass the container a list of value types without value names:
>
> auto c2 = Container!(size_t, real, real)();
> c2.add(5, 3.2, 5.6);
> writeln(c2);
> writeln();
>
> ... but if I try asking the container to store a tuple with _named_ values, e.g.
>
> auto c3 = Container!(size_t, real, "value")();
>
> then compilation fails with the following error message:
>
> --------------------------------------------------------------------------------
> tupcontainer.d(7): Error: tuple Properties is used as a type
> tupcontainer.d(12): Error: template
> std.typecons.Tuple!(ulong,"id",real,"value").Tuple.__ctor does not match any
> function template declaration
> /usr/local/include/d2/std/typecons.d(406): Error: template
> std.typecons.Tuple!(ulong,"id",real,"value").Tuple.__ctor cannot deduce template
> function from argument types !()(ulong,_error_)
> tupcontainer.d(51): Error: template instance
> tupcontainer.Container!(ulong,real,"value") error instantiating
> --------------------------------------------------------------------------------
>
> I'm confused as to why the Container struct cannot take these template
> parameters when the corresponding parameters work just fine for Tup.
>
> Can anyone advise what the problem is and if it's possible to get the Container
> working as envisioned?
std.typecons.Tuple does a bit of magic behind the scenes. This includes
ridding itself of non-type parameters.
Simply put, you can imagine inserting the type tuple directly into the
function definition:
void add(ID id, size_t arg0, real arg1, "value" arg2);
as you probably notice, the last argument looks weird.
Now, Phobos does not currently have a staticFilter template, nor does it
have an isType template, so here are implementations of those:
template staticFilter( alias pred, T... ) {
static if ( T.length == 0 ) {
alias TypeTuple!( ) staticFilter;
} else static if ( pred!( T[0] ) ) {
alias TypeTuple!( T[0], staticFilter!( pred, T[1..$] ) ) staticFilter;
} else {
alias staticFilter!( pred, T[1..$] ) staticFilter;
}
}
unittest {
static struct S(T...){}
assert( is( S!(staticFilter!(isType, int, float)) == S!(int, float) ) );
assert( is( S!(staticFilter!(isType, int, "foo", float)) == S!(int, float) ) );
assert( is( S!(staticFilter!(isType, "foo", "bar")) == S!() ) );
}
template isType( T... ) if ( T.length == 1 ) {
enum isType = !is( typeof( T[0] ) );
}
unittest {
struct S {}
class C {}
assert( isType!int );
assert( isType!string );
assert( isType!S );
assert( isType!C );
assert( !isType!1 );
assert( !isType!"" );
assert( !isType!(S( )) );
}
add would then have this signature:
void add(ID id, staticFilter!(isType, Properties));
--
Simen
|