イントロスペクション エミュレーション ? それは挑戦のように聞こえますが、それは確かです。
インターフェイスはあまり気に入らないので、別の方法を提案します。
struct MyType
{
int fieldA;
int fieldB;
void setField(std::string const& field, std::string const& value);
};
ここでの課題は、setField
適切なフィールドを選択することであり、実際にマップが適切であるように思われます。ただし、型情報をどこかにカプセル化する必要があるため (int のみを使用する予定がない限り、その場合は問題はありません)、ファンクタのマップが適切です。
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 :)
}
};
の使用に注意してくださいstd::istringstream
。std::istream
. したがって、ユーザー定義のクラスをサポートできます。
そしてもちろん、ここでの部分はすべて自動化に関するものです!
そして、マクロのような自動化。
#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_)
このような使い方:
// 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");
もちろん、通常の警告が適用されます。頭のてっぺんから、コンパイルしたことがなく、子猫を殺す可能性があり、さらに悪いことです。