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