On Thu, Aug 5, 2010 at 04:26, bearophile <bearophileh...@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