digitalmars.D - Test for self referential templated Class
- Manfred Nowak (15/15) Jun 29 2008 Seems, that tests for the type of a self referential templated class
- janderson (4/23) Jun 29 2008 pragma( msg, Format!(is(T:C!(--> C!(int) <--- )))); //recursive expansi...
- Manfred Nowak (5/7) Jun 29 2008 ... but if this is true, then I have to implement a stopping condition
- Koroskin Denis (4/11) Jun 30 2008 Use tango.core.Variant.isAtomicType!(T) template to test against builtin...
- Manfred_Nowak (9/11) Jun 30 2008 .. this does not help for user defined types.
- Robert Fraser (2/18) Jun 30 2008 Make it derive from a (non-templated) interface and test for that.
- Manfred_Nowak (24/25) Jun 30 2008 Yes, this seems to be a part of the solution. With this hack every
- Michel Fortin (14/21) Jun 30 2008 You could add a dummy member in C!(T) and check for its presence.
- Manfred_Nowak (23/24) Jun 30 2008 Yes. That seems to be less hackish than what Robert suggested. But
- Don (18/46) Jun 30 2008 I've done this sort of thing with a recursive mixin.
- Fawzi Mohamed (23/29) Jul 02 2008 I simply use two templates, one to give me the depth of recursion, one
- JAnderson (11/22) Jun 30 2008 ic,
- JAnderson (3/32) Jun 30 2008 There's also typeof(this).
Seems, that tests for the type of a self referential templated class are impossible, because recursive expansion is forbidden. Am I missing something? Example: import std.metastrings; class C(T){ pragma( msg, Format!(is(T:C!(int)))); //pragma( msg, Format!(is(T:C!(C!(int))))); //recursive expansion forbidden } void main(){ auto c1= new C!( C!(int)); auto c2= new C!( C!( C!(int))); } -manfred
Jun 29 2008
Manfred Nowak wrote:Seems, that tests for the type of a self referential templated class are impossible, because recursive expansion is forbidden. Am I missing something? Example: import std.metastrings; class C(T){ pragma( msg, Format!(is(T:C!(int)))); //pragma( msg, Format!(is(T:C!(C!(int))))); //recursive expansion forbidden } void main(){ auto c1= new C!( C!(int)); auto c2= new C!( C!( C!(int))); } -manfredpragma( msg, Format!(is(T:C!(--> C!(int) <--- )))); //recursive expansion C!(int) will call itself forever. You need a stopping condition like template specialization or an static if.
Jun 29 2008
janderson wrote:You need a stopping condition like template specialization or an static if.... but if this is true, then I have to implement a stopping condition or a static if for _every possible_ actual type ( int, uint, ...)---and the generic achievenment is lost. -manfred
Jun 29 2008
On Mon, 30 Jun 2008 10:53:34 +0400, Manfred Nowak <svv1999 hotmail.com> wrote:janderson wrote:Use tango.core.Variant.isAtomicType!(T) template to test against builtin types.You need a stopping condition like template specialization or an static if.... but if this is true, then I have to implement a stopping condition or a static if for _every possible_ actual type ( int, uint, ...)---and the generic achievenment is lost. -manfred
Jun 30 2008
Koroskin Denis wrote:Use tango.core.Variant.isAtomicType!(T) template to test against builtin types... this does not help for user defined types. One seem's to need something like class C(T){ //... !is( T == C!( ... )) But this casts one into infinite recursion. -manfred
Jun 30 2008
Manfred_Nowak wrote:Koroskin Denis wrote:Make it derive from a (non-templated) interface and test for that.Use tango.core.Variant.isAtomicType!(T) template to test against builtin types... this does not help for user defined types. One seem's to need something like class C(T){ //... !is( T == C!( ... )) But this casts one into infinite recursion. -manfred
Jun 30 2008
Robert Fraser wrote:Make it derive from a (non-templated) interface and test for that.Yes, this seems to be a part of the solution. With this hack every instance can check whether the given type T belongs to any instance of C's family of instances. But it seems still not possible to identify an instance on a specified non trivial depth of recursion: import std.metastrings; interface Hack{}; class C(T):Hack{ pragma( msg, Format!(is( T: Hack))); pragma( msg, Format!(is( T== int))); pragma( msg, Format!(is( T== C!( int)))); //pragma( msg, Format!(is( T== C!( C!( int))))); //recursion //pragma( msg, Format!(is( T== C!( C!( C!( int)))))); //recursion } //class C(T:C!( C!(int))){ } void main(){ auto c1= new C!(int); pragma( msg, "c1 done"); auto c2= new C!( C!(int)); pragma( msg, "c2 done"); auto c3= new C!( C!( C!(int))); pragma( msg, "c3 done"); } -manfred
Jun 30 2008
On 2008-06-30 03:56:54 -0400, "Manfred_Nowak" <svv1999 hotmail.com> said:One seem's to need something like class C(T){ //... !is( T == C!( ... )) But this casts one into infinite recursion.You could add a dummy member in C!(T) and check for its presence. Something like: struct IsCTemplate {} class C(T) { static const IsCTemplate isCTemplate; //... } Then you can use this go check if you have a C!(...) or not: is(T.isCTemplate == IsCTemplate) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 30 2008
Michel Fortin wrote:You could add a dummy member in C!(T) and check for its presence.Yes. That seems to be less hackish than what Robert suggested. But still no possibility to fetch a non trivial depth of recursion. import std.metastrings; private typedef int TID; // TypeID for checking purposes class C(T){ alias .TID TID; pragma( msg, Format!(is( T.TID== TID))); } class D{ private typedef int TID; } void main(){ auto d= new C!( D); pragma( msg, "d done"); auto c1= new C!(int); pragma( msg, "c1 done"); auto c2= new C!( C!(int)); pragma( msg, "c2 done"); auto c3= new C!( C!( C!(int))); pragma( msg, "c3 done"); } -manfred
Jun 30 2008
Manfred_Nowak wrote:Michel Fortin wrote:I've done this sort of thing with a recursive mixin. The basic idea is something like char [] testRecursion(bool done) { return done? `true`: `mixin("testRecursion( XXX)`; } template isRecursive(T) { const bool isRecursive = mixin(testRecursion()); } where XXX is some expression involving T. It works because if the condition isn't true, the recursive bit is just a string which is never parsed. But if it is true, it gets mixed in recursively. There might be something a bit less hacky for this situation*. But the recursive mixin trick will work even for fiendishly difficult cases. You can hide any old garbage that wouldn't normally compile for ANY reason. * for D2.0, you can probably use __traits(compiles, XXX)You could add a dummy member in C!(T) and check for its presence.Yes. That seems to be less hackish than what Robert suggested. But still no possibility to fetch a non trivial depth of recursion.import std.metastrings; private typedef int TID; // TypeID for checking purposes class C(T){ alias .TID TID; pragma( msg, Format!(is( T.TID== TID))); } class D{ private typedef int TID; } void main(){ auto d= new C!( D); pragma( msg, "d done"); auto c1= new C!(int); pragma( msg, "c1 done"); auto c2= new C!( C!(int));; pragma( msg, "c2 done"); auto c3= new C!( C!( C!(int))); pragma( msg, "c3 done"); } -manfred
Jun 30 2008
On 2008-06-30 21:53:40 +0200, "Manfred_Nowak" <svv1999 hotmail.com> said:Michel Fortin wrote:I simply use two templates, one to give me the depth of recursion, one to give the base type... This is for arrays, but it can be adapted also for other types /// Strips the []'s off of a type. template arrayBaseT(T) { static if( is( T S : S[]) ) { alias arrayBaseT!(S) arrayBaseT; } else { alias T arrayBaseT; } } /// Count the []'s on an array type template arrayRank(T) { static if(is(T S : S[])) { const uint arrayRank = 1 + arrayRank!(S); } else { const uint arrayRank = 0; } } FawziYou could add a dummy member in C!(T) and check for its presence.Yes. That seems to be less hackish than what Robert suggested. But still no possibility to fetch a non trivial depth of recursion.
Jul 02 2008
Manfred Nowak wrote:janderson wrote:ic, What about calling another template? class A(T){ ... } class C(T){ pragma( msg, Format!(is(T:C!(A!(int))))); } Although I'm not exactly sure what your trying to do. -JoelYou need a stopping condition like template specialization or an static if.... but if this is true, then I have to implement a stopping condition or a static if for _every possible_ actual type ( int, uint, ...)---and the generic achievenment is lost. -manfred
Jun 30 2008
JAnderson wrote:Manfred Nowak wrote:There's also typeof(this). -Joeljanderson wrote:ic, What about calling another template? class A(T){ ... } class C(T){ pragma( msg, Format!(is(T:C!(A!(int))))); } Although I'm not exactly sure what your trying to do. -JoelYou need a stopping condition like template specialization or an static if.... but if this is true, then I have to implement a stopping condition or a static if for _every possible_ actual type ( int, uint, ...)---and the generic achievenment is lost. -manfred
Jun 30 2008