The basic concept behind this technology is the ability to know rather arbitrary aspects of an object's type at runtime, long after the compiler has thrown that information away. Other object oriented systems (for example Objective C) use dynamic type binding in the form of an isa pointer that points to a compiler generated object representing the class of that object. This technology can also referred to as class description, as one only needs to generate a description of the object's class, then ensure the object is bound to that description, hence the name classdesc[3].
In C++, it is not necessary to incur the overhead of an isa pointer, as one can bind an object's type to an overloaded instance of a function call at compile time.
A descriptor is a template function D
template <class T> void D(D_t& t, const classdesc::string& d, T& a);
The D t argument allows for state to be maintained while the descriptor is recursively applied to the data structure. If state is not needed for the descriptor, a “null” object should be provided for passing through.
Users can specialise the descriptor to handle different types. The
classdesc descriptor, however does not specialise the descriptor
directly, but rather specialises a functor template:
template <class T> struct access_D { void operator()(D_t&, const string&, T&); };There are two advantages of using functional classes:
operator()
of the appropriate
access class, eg:
template <class T> void pack(classdesc::pack_t& t, const classdesc::string& d, T& a) {classdesc::access_pack<T>()(t,d,a);}but may optionally perform some additional pre/post-processing if sensible for the particular descriptor.
The classdesc package comes with several descriptors already implemented:
struct pack_t { char *data(); const char *data() const; size_t size(); } buf;A call to
pack(buf,""",foo)
pushes a binary representation of
the object foo (regardless of its type) into buf. The inverse
operation is called unpack. Syntactically, we may also use the
<<
operator for the same purpose:
buf << foo << bar; fwrite(buf.data(),buf.size(),1,f); pack_t b1(buf.size()); fread(b1.data(),b1.size(),1,f); b1 >> foo1 >> bar1;This code has made a copy of foo and bar, but with the data going via a disk file.