www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Test for self referential templated Class

reply Manfred Nowak <svv1999 hotmail.com> writes:
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
parent reply janderson <askme me.com> writes:
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)));
 }
 
 -manfred

pragma( 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
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
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
next sibling parent reply "Koroskin Denis" <2korden gmail.com> writes:
On Mon, 30 Jun 2008 10:53:34 +0400, Manfred Nowak <svv1999 hotmail.com>  
wrote:

 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

Use tango.core.Variant.isAtomicType!(T) template to test against builtin types.
Jun 30 2008
parent reply "Manfred_Nowak" <svv1999 hotmail.com> writes:
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
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Manfred_Nowak wrote:
 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

Make it derive from a (non-templated) interface and test for that.
Jun 30 2008
parent "Manfred_Nowak" <svv1999 hotmail.com> writes:
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
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
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
parent reply "Manfred_Nowak" <svv1999 hotmail.com> writes:
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
next sibling parent Don <nospam nospam.com.au> writes:
Manfred_Nowak wrote:
 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.

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)
 
 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
prev sibling parent Fawzi Mohamed <fmohamed mac.com> writes:
On 2008-06-30 21:53:40 +0200, "Manfred_Nowak" <svv1999 hotmail.com> said:

 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.

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; } } Fawzi
Jul 02 2008
prev sibling parent reply JAnderson <ask me.com> writes:
Manfred Nowak wrote:
 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

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. -Joel
Jun 30 2008
parent JAnderson <ask me.com> writes:
JAnderson wrote:
 Manfred Nowak wrote:
 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

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. -Joel

There's also typeof(this). -Joel
Jun 30 2008