digitalmars.D.learn - tupleof for inherited classes.
[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
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