Tuples and variable-length template parameter lists

Simen Kjaeraas simen.kjaras at gmail.com
Mon Nov 5 09:14:28 PST 2012


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


More information about the Digitalmars-d-learn mailing list