One question about templates
Philippe Sigaud
philippe.sigaud at gmail.com
Wed Aug 4 23:17:47 PDT 2010
On Thu, Aug 5, 2010 at 04:26, bearophile <bearophileHUGS at lycos.com> wrote:
> I have found one bad looking solution :-)
>
> template IsFoo(alias S) {
> enum bool IsFoo = __traits(compiles, { void isf(T...)(Foo!T){}
> isf(S.init); });
> }
>
I used to be confronted to this pb too. Here is what I did:
/**
Alias itself to true if $(M T) is an instance of $(M templ). To obtain the
template parameters,
see TemplateParametersTypeTuple.
Example:
----
auto cy = cycle([0,1,2,3]); // cy is a Cycle!(int[])
alias typeof(cy) Cy;
assert(isInstanceOf!(Cy, Cycle));
----
*/
template isInstanceOf(T, alias templ)
{
static if (T.stringof.length >= __traits(identifier, templ).length
&& T.stringof[0..__traits(identifier, templ).length] ==
__traits(identifier, templ))
enum bool isInstanceOf = true;
else
enum bool isInstanceOf = false;
}
/**
Alias itself to true iff templ is a template name (standard, function, class
or struct template).
*/
template isTemplate(alias templ)
{
static if (is(typeof(templ) == void) && is(typeof(templ.stringof)))
enum bool isTemplate = true;
else
enum bool isTemplate = false;
}
The converse is a bit more complicated: given a type T, of which you know
it's a template instantiation (T == U!someTypes), get the (someTypes) as a
typetuple.
string[3] between(char b, char e, string s)()
{
int foundb;
int ib;
string notFound = "";
foreach(i,c; s)
{
if (c==b)
{
if (foundb == 0)
{
foundb = 1;
ib = i+1;
continue;
}
else
{
++foundb;
}
}
if (c==e)
{
if (foundb == 1)
{
return [s[0..ib-1], s[ib..i], s[i+1..$]]; // before b,
between b and e, after e. Standard case.
}
else
{
--foundb;
}
}
}
return [s, notFound,notFound]; // no b found, explored the whole string
}
/**
Takes a type instantiating a template (that is, T == A!(someTypes...) for
some A)
and becomes the template's parameters typetuple: TypeTuple!(someTypes) in
the previous example.
It won't work for alias parameters, because they're not imported.
Example:
----
assert(is(TemplateParametersTypeTuple!(Cycle!(int[])) ==
TypeTuple!(int[])));
----
*/
template TemplateParametersTypeTuple(T)
{
mixin("alias TypeTuple!(" ~ between!('(',')',T.stringof)[1] ~ ")
TemplateParametersTypeTuple;");
}
As a nice side-effect, you can also extract the template name:
/**
If T is a template instantiation, becomes the template name. For a
non-templated type,
it just becomes this type name.
----
struct Foo(T...) {}
alias Foo!(int, double) Foo_id;
assert(TemplateName!(Foo_id) == "Foo");
assert(TemplateName!(int) == "int");
----
*/
template TemplateName(T)
{
enum string TemplateName = between!('!','(',T.stringof)[0];
}
So, given T, you can
- determine if it's a template instantiation or not (TBD)
- extract the template name (and so, test for their equality)
- extract the template parameters, as a TypeTuple
I used this to transfer template parameters from one template to another:
FromXToBar(someFoo)
-> test if it's a template
-> extract the parameters
-> instantiate a Bar!Parameters.
So, given a Bar!(int,double), it creates a Foo!(int,double). It's a kind of
function, from Bar to Foo...
It worked for me, tell me if it's OK for you.
Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-learn/attachments/20100805/066950eb/attachment.html>
More information about the Digitalmars-d-learn
mailing list