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