Introspection emulation ? That sounds like a challenge, that s for sure.
The interface does not really please me, so I would propose an alternative:
struct MyType
{
int fieldA;
int fieldB;
void setField(std::string const& field, std::string const& value);
};
Now the challenge is for setField
to select the right field, and indeed a map seems appropriate. However we need to encapsulate the type information somewhere (unless you plan on using only ints, in which case... there is no difficulty), so a map of functors is in order.
static std::map<std::string, Functor<MyType>*> M_Map;
// where Functor is
template <class Type>
struct Functor
{
virtual void set(Type& t, std::string const& value) const = 0;
};
// And a specialization would be
struct SetfieldA : public Functor<MyType>
{
virtual void set(MyType& t, std::string const& value) const
{
std::istringstream stream(value);
stream >> t.fieldA;
// some error handling could be welcome there :)
}
};
Note the use of std::istringstream
, now you can support any type as long as they correctly interact with an std::istream
. Thus you can support user defined classes.
And of course, the part here is all about automation!
And automation like in macros.
#define INTROSPECTED(MyType_)
private:
typedef Functor<MyType_> intro_functor;
typedef std::map<std::string, intro_functor const*> intro_map;
static intro_map& IntroMap() { static intro_map M_; return M_; }
public:
static void IntroRegister(std::string const& field, intro_functor const* f){
IntroMap()[field] = f; }
void setField(std::string const& field, std::string const& value) {
intro_map::const_iterator it = IntroMap().find(field);
if (it != IntroMap().end()) it->second->set(*this, value); }
#define INTROSPECT_FIELD(Class_, Name_)
struct Set##Name_: public Functor<Class_> {
virtual void set(Class_& t, std::string const& value) {
std::istringstream stream(value); stream >> t.Name_; } } Setter##Name_;
Class_::IntroRegister(#Name_, Setter##Name_)
Usage like this:
// myType.h
struct MyType
{
INTROSPECTED(MyType);
int fieldA;
int fieldB;
};
// myType.cpp
INTROSPECT_FIELD(MyType, fieldA);
INTROSPECT_FIELD(MyType, fieldB);
// Any file
MyType t;
t.set("fieldA", "3");
Of course the usual caveat apply: off the top of my head, never compiled it, may kill kittens and worse.