Boost logo

Boost :

From: Stefan Roiser (stefan.roiser_at_[hidden])
Date: 2006-01-29 17:17:07


Hi,

We would like to propose a library and tools which enhance C++ with
reflection capabilities. The package, "Reflex", provides a library
for runtime introspection and interaction with C++ "constructs" such
as objects, types, scopes, members, templated types, ... The library
has no external dependencies and was developed with the ISO/IEC
standard for C++ as guideline.

Production of dictionary information of arbitrary C++ definitions is
done via a Python script (genreflex), in a non-intrusive way, using
an external tool (gccxml - www.gccxml.org). The generated dictionary
source code can be compiled into a shared library, dynamically loaded
and accessed via an API providing the introspection information.

You can find more information at

http://cern.ch/reflex

Below you may find an example code snippet which exposes a subset of
the functionality. The four different parts show
1 - the definition of the example classes
2 - how to generate the dictionary information
3 - example on introspection (re-generate classes from the dictionary
information)
4 - examples on interaction (get/set data members, invoke functions,
con/destruct objects)

Cheers

     Stefan

//
// 1. original class Foo.h
//

namespace zot {

   struct foo_base {
   public:
     foo_base() : fBar(4711) {}
     ~foo_base() {}
   protected:
     int fBar;
   };

   class foo : public foo_base {
   public:
     int bar();
     void set_bar(int i);
     void set_bar(float f);
     void operator ++ ();
   };

   inline int foo::bar() { return fBar; }
   inline void foo::set_bar(float f) { fBar = int(f); }
   inline void foo::set_bar(int i) { fBar = i; }
   inline void foo::operator ++ () { ++fBar; }

} // namespace zot

//
// 2. Run python script on Foo.h generating dictionary source code
// (Foo_rflx.cpp) and produce a shared library libFooRflx.so
//

genreflex Foo.h --gccxmlpath=/dir/to/gccxml/bin
(e.g.) g++ -shared -o libFooRflx.so Foo_rflx.cpp -I${REFLEXROOT}/
include -L${REFLEXROOT}/lib -lReflex

//
// 3. + 4. example code for introspection and interaction
//

#include "Reflex/Reflex.h"

using namespace std;
using namespace ROOT::Reflex;
enum Visibility { Public, Protected, Private };

void generate_class_decl( const Type & cl,
                           const string & indent ) {

   // ... base class declarations
   if ( cl.BaseSize()) {
     for ( Base_Iterator b = cl.Base_Begin(); b != cl.Base_End(); ++b)
       generate_class_decl((*b).ToType(), indent);
   }

   cout << indent << "class " << cl.Name();

   // ... bases
   if ( cl.BaseSize()) {

     cout << " : " ;

     for ( Base_Iterator b = cl.Base_Begin(); b != cl.Base_End(); +
+b ) {

       if ( (*b).IsVirtual() ) cout << "virtual ";
       if ( (*b).IsPublic() ) cout << "public ";
       if ( (*b).IsProtected() ) cout << "protected ";
       if ( (*b).IsPrivate() ) cout << "private ";

       cout << (*b).ToType().Name(SCOPED);

       if ( b != cl.Base_End()-1 ) cout << ", ";
     }
   }

   cout << " {" << endl;

   Visibility vis = Private;

   // ... function members
   for ( Member_Iterator f = cl.FunctionMember_Begin(); f !=
cl.FunctionMember_End(); ++f ) {

     if ( ! (*f).IsArtificial()) {

       if ( (*f).IsPublic() && vis != Public ) {
         cout << indent << "public:" << endl;
         vis = Public;
       }
       else if ( (*f).IsProtected() && vis != Protected ) {
         cout << indent << "protected:" << endl;
         vis = Protected;
       }
       else if ( (*f).IsPrivate() && vis != Private ) {
         cout << indent << "private:" << endl;
         vis = Private;
       }

       Type ft = (*f).TypeOf();

       cout << indent + " ";

       if ( ! (*f).IsConstructor() && !(*f).IsDestructor() )
         cout << ft.ReturnType().Name(SCOPED) << " ";

       if ( (*f).IsOperator() ) cout << "operator ";
       cout << (*f).Name() << " (";

       if ( ft.FunctionParameterSize() ) {
         for ( size_t p = 0 ; p < ft.FunctionParameterSize(); p++ ) {
           cout << ft.FunctionParameterAt(p).Name(SCOPED|QUALIFIED);

           if ( (*f).FunctionParameterNameAt(p).length() )
             cout << " " << (*f).FunctionParameterNameAt(p);

           if ( (*f).FunctionParameterDefaultAt(p).length() )
             cout << " = " << (*f).FunctionParameterDefaultAt(p);

           if ( p != ft.FunctionParameterSize()-1 ) cout << ", ";
         }
       }
       cout << ");" << endl;
     }
   }

   // ... data members
   for ( Member_Iterator d = cl.DataMember_Begin(); d !=
cl.DataMember_End(); ++d ) {

     if ( (*d).IsPublic() && vis != Public ) {
       cout << indent << "public:" << endl;
       vis = Public;
     }
     else if ( (*d).IsProtected() && vis != Protected ) {
       cout << indent << "protected:" << endl;
       vis = Protected;
     }
     else if ( (*d).IsPrivate() && vis != Private ) {
       cout << indent << "private:" << endl;
       vis = Private;
     }
     cout << indent + " " << (*d).TypeOf().Name(SCOPED)
          << " " << (*d).Name() << ";" << endl;
   }
   cout << indent << "};" << endl;
}

void generate_class(const Type & ty) {

   string indent = "";
   Scope sc = ty.DeclaringScope();

   // ... declaring scope
   if ( ! sc.IsTopScope() ) {
     if (sc.IsNamespace()) cout << "namespace ";
     else if (sc.IsClass()) cout << "class ";

     cout << sc.Name() << " {" << endl;
     indent += " ";
   }

   generate_class_decl(ty, indent);

   if ( ! sc.IsTopScope() ) {
     cout << "}" << endl;
     if (sc.IsClass()) cout << ";";
   }
}

int main() {

   // load the dictionary information
   void * v = dlopen("libFooRflx.so", RTLD_LAZY);

   // get meta information of type Foo
   Type fooType = Type::ByName("zot::foo");

   // check if the type is valid
   if (fooType) {

     //
     // 3. Introspection
     //

     // generate declarations for foo
     generate_class(fooType);

     //
     // 4. Interaction
     //

     // update the information for inherited members of class foo
     // this will be automatic in the future
     fooType.UpdateMembers();

     // construct an object of type Foo
     Object fooObj = fooType.Construct();

     // get the value of the data member (i.e. 4711)
     int val = Object_Cast<int>(fooObj.Get("fBar"));

     // set the data member to 4712
     fooObj.Set("fBar",++val);
     // get the data member again (i.e. 4712)
     val = Object_Cast<int>(fooObj.Get("fBar"));

     // call function setBar with value 4713
     fooObj.Invoke("set_bar",Type::ByName("void (int)"), ++val);
     // call operator ++ to increase fBar by one
     fooObj.Invoke("operator++");
     // call bar getter and cast the output to int (i.e. 4714)
     val = Object_Cast<int>(fooObj.Invoke("bar"));

     // delete the Foo object
     fooObj.Destruct();
   }

   return 0;

}

/*
//
// the output of the introspection part is
//

namespace zot {
   class foo_base {
   public:
     foo_base ();
     ~foo_base ();
   protected:
     int fBar;
   };
   class foo : public zot::foo_base {
   public:
     int bar ();
     void set_bar (int i);
     void set_bar (float f);
     void operator operator++ ();
   };
}

//
//
//
*/

-- 
Stefan Roiser
CERN, PH Department
CH - 1211 Geneva 23
Mob:+41 76 487 5334
Tel:+41 22 767 4838
Fax:+41 22 767 9425

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk