www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - tupleof for inherited classes.

reply "mrdarksys" <mrdarksys gmail.com> writes:
[Problem]
How can I use enumFields() function of Engine class for enumerate 
all fields of inherited classes?
I want to do without templates if possibly.

Code [example]:
//============
import std.stdio;

class Engine
   {
     public:
       int publicField;

       void enumFields()
         {
           writeln("Engine prints:");
           foreach(ref field; this.tupleof)
             writeln(field);
         }

     private:
       bool privateField;

     protected:
       string protectedField = "s";
   }

class Some : Engine
   {
     public:
       int oneMoreField = 11;

       void enumFields2()
         {
           writeln("Some prints:");
           foreach(field; this.tupleof)
             writeln(field);
         }

     protected:
       string protectedField = "o";
   }

int main()
   {
     auto objE = new Engine();
     auto objS = new Some();

     objE.enumFields();

     objS.publicField = 4;

     objS.enumFields();

     objS.enumFields2();

     return 0;
   }
//==============

[Actual] output is:
//==============
Engine prints:
0
false
s
Engine prints:
4
false
s
Some prints:
11
o
//==============

[Expected] output is:
//==============
Engine prints:
0
false
s
Engine prints:
4
false
o
11
Some prints:
4
false
o
11
//==============
Jul 24 2012
parent "Chris NS" <ibisbasenji gmail.com> writes:
I know you specifically asked for a way to do this without 
templates, but this was my first thought on how to make it work 
(and I confirmed it):

##############################
import  std.stdio   ,
         std.traits  ;

class Engine {

     int publicField ;

     void enumFields ( this Self ) ( bool heading = true ) {
         auto self = cast( Self ) this;
         if ( heading ) {
             writeln( "Engine prints:" );
         }
         foreach( base ; BaseClassesTuple!Self ) {
             static if ( is( base : Engine ) ) {
                 ( cast( base ) self ).enumFields( false );
             }
         }
         foreach( ref field ; self.tupleof ) {
             writeln( '\t', field );
         }
     }

     protected string protectedField = "s" ;

     private bool privateField ;

}

class Some : Engine {

     int oneMoreField = 11;

     void enumFields2 () {
         writeln( "Some prints:" );
         foreach( field ; this.tupleof ) {
             writeln( '\t', field );
         }
     }

     protected string protectedField = "o";

}

void main () {
     auto objE = new Engine;
     auto objS = new Some;

     objE.enumFields();

     objS.publicField = 4;
     objS.enumFields();
     objS.enumFields2();

     ( cast( Engine ) objS ).enumFields();
}
##############################

The downside is that the reference you invoke enumFields() 
against must be of the lowest type to get all members, as that 
last line demonstrates.  Beyond this, I don't believe there is 
any way for methods defined by Engine to see members of derived 
classes.  The first alternative I could think of, is to use NVI 
(non-virtual interfaces).

##############################
import  std.stdio   ;

class Engine {

     int publicField ;

     final void enumFields () {
         writeln( this.classinfo.name, " prints:" );
         enumFieldsImpl();
     }

     protected string protectedField = "s" ;

     protected void enumFieldsImpl () {
         foreach ( field ; this.tupleof ) {
             writeln( '\t', field );
         }
     }

     private bool privateField ;

}

class Some : Engine {

     int oneMoreField = 11;

     protected override void enumFieldsImpl () {
         super.enumFieldsImpl();
         foreach ( field ; this.tupleof ) {
             writeln( '\t', field );
         }
     }

     protected string protectedField = "o";

}

void main () {
     auto objE = new Engine;
     auto objS = new Some;

     objE.enumFields();

     objS.publicField = 4;
     objS.enumFields();

     ( cast( Engine ) objS ).enumFields();
}
##############################

This works even in the last (previously degenerate) case, however 
it naturally results in code duplication.  Depending on what your 
real scenario is, however, that may not be a severe issue.

-- Chris NS
Jul 25 2012