
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