digitalmars.D.learn - One question about templates
- bearophile (15/15) Aug 04 2010 How can I tell that S1 and S2 are different instantiations of the same s...
- bearophile (16/16) Aug 04 2010 Something simpler is enough for my purposes, to tell that a type is one ...
- bearophile (6/6) Aug 04 2010 I have found one bad looking solution :-)
- Philippe Sigaud (117/122) Aug 04 2010 I used to be confronted to this pb too. Here is what I did:
- bearophile (35/37) Aug 05 2010 You are gentle and helpful, and your post has given me useful ideas, but...
- Philippe Sigaud (9/18) Aug 05 2010 Oww, what a mess!
- Philippe Sigaud (127/128) Aug 05 2010 OK, let's try again.
- bearophile (4/5) Aug 05 2010 Thank you for all your code :)
How can I tell that S1 and S2 are different instantiations of the same struct template, while Bar is an instantiation of a different struct template? struct Foo(T...) {} struct Bar(T...) {} template SameStructTemplate(S1, S2) { // enum bool SameStructTemplate = ? } void main() { alias Foo!(int,int,int) S1; alias Foo!(float,int,int,int) S2; alias Bar!(float,int,int,int) S3; static assert(SameStructTemplate!(S1, S2)); static assert(!SameStructTemplate!(S1, S3)); } Bye and thank you, bearophile
Aug 04 2010
Something simpler is enough for my purposes, to tell that a type is one instantiation of Foo or not: struct Foo(T...) {} struct Bar(T...) {} template IsFoo(S) { // ? } void main() { alias Foo!(int,int,int) S1; alias Foo!(float,int,int,int) S2; alias Bar!(float,int,int,int) S3; static assert(IsFoo!S1); static assert(IsFoo!S2); static assert(!IsFoo!S3); } Bye, bearophile
Aug 04 2010
I have found one bad looking solution :-) template IsFoo(alias S) { enum bool IsFoo = __traits(compiles, { void isf(T...)(Foo!T){} isf(S.init); }); } Bye, bearophile
Aug 04 2010
On Thu, Aug 5, 2010 at 04:26, bearophile <bearophileHUGS 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
Aug 04 2010
Philippe Sigaud:I used to be confronted to this pb too. Here is what I did: ...You are gentle and helpful, and your post has given me useful ideas, but your post it too much unreadable for me. If you take a look here you can see 16 attaches, and it seems part of your message are missing, where is the code for TemplateName? And what does it happen if two templates coming from two modules share the same name? http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=20943 Through your post I have found this, that can't be used to solve my problem, but seems interesting and worth putting into Phobos2 if not already present: private string[3] _between(char b, char e, string s)() { int foundb, 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 .. $]]; else foundb--; } } return [s, notFound, notFound]; } template TemplateParameters(T) { mixin("alias TypeTuple!(" ~ _between!('(', ')' , T.stringof)[1] ~ ") TemplateParameters;"); } But in the end I have not understood how you suggest me to solve my problem, sorry :-) Writing code like this is not a good idea because I think it instantiates extraneous templates: assert(is(Foo!(TemplateParameters!(S1)) == S1)); Bye, bearophile
Aug 05 2010
bearophile Wrote:Philippe Sigaud:Oww, what a mess! That's strange, I didn't do anything different from all other answers. Man, are my posts always like this? I'd be horrified to pollute the NG like this. I did not attach anything or whatever, just replied to you mail. The code I pasted was complete and functional. I don't have it here, I'll answer again tonight, using the digitalmars website.I used to be confronted to this pb too. Here is what I did: ...You are gentle and helpful, and your post has given me useful ideas, but your post it too much unreadable for me. If you take a look here you can see 16 attaches, and it seems part of your message are missing, where is the code for TemplateName?And what does it happen if two templates coming from two modules share the same name?Good question. The names returned by .stringof or __traits(identifier) are always short, not fully qualified. Just this week, I needed to get a qualified name and could not found a way. I can start a thread about it on the D main NG. Maybe doing a static import would work? Philippe
Aug 05 2010
OK, let's try again. I used to be confronted to this pb too. Here is what I did: /** Alias itself to true if T is an instance of 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. /** CTFE function to search a string s for a begin char b and an end char e. returns [s[0..index of b], s[index of b+1, index of e], s[index of e+1, .. $]] Above all else, it's done for a pair of enclosing chars, like ( and ) As such, it does not stop at the first ')' after a '(' but will count the correct numbers of parenthesis. So, between!('(',')', "Foo!(A, B!(int, double), C)") will return ["Foo!", "A,B!(int,double),C", ""] and _not_ ["Foo!", "A,B!(int,double", ", C)"] This may not work so well with non-paired characters. */ 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: ToBar(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 any templated type to Foo... A sort of projection, if you will.And what does it happen if two templates coming from two modules share the same name?Say I have a Foo in module A, another in module B. In my main module, when I create a Foo, I have to indicate if that's a A.Foo or a B.Foo. Similarly, any use of Foo has to be qualified, or else the compiler will complain. Halas, it then cuts all qualifiying information from the names :( So: alias A.Foo!(int, double) S1; isInstanceOf(S1, Foo; // Foo does not exist -> doesn't compile isInstanceOf(S1, A.Foo); // compiles, returns true; isInstanceOf(S1, B.Foo); // compiles also (OK), returns true (NOK !) I tested with a static import and it did not change anything. Philippe
Aug 05 2010
Philippe Sigaud:I used to be confronted to this pb too. Here is what I did:Thank you for all your code :) Bye, bearophile
Aug 05 2010