Потребовалось тут недавно иметь возможность обращаться к полю в структуре по её имени — записать, прочитать значение. И так, чтобы производительность тех мест, где это не используется не изменилась.
Вот что получилось:
Весь секрет в «волшебных пузырьках» — в классе от которого наследуется TUser, и одной функции — StoreValue().
Подробности под катом.
Важно: Данное решение кросплатформенно, требует только STL и компилятора C++, который «умеет» шаблоны.
Вначале — синонимы типов — для того, чтобы в случае экспериментов — было проще менять.
Базовый класс, который и обеспечивает «вкусности»
А вот так вот мы от него наследуемся:
Вот что получилось:
Copy Source | Copy HTML
- TUser user;
- user.StoreValue();
- double SalaryRef;
- user.SetField("Salary", SalaryRef); // сохранили
- user.GetField("Salary", SalaryRef); // загрузили - передача по ссылке
-
- // можно ещё и так, но сами понимаете - не удобно
- double Salary = user.GetField<double>("Salary");
Весь секрет в «волшебных пузырьках» — в классе от которого наследуется TUser, и одной функции — StoreValue().
Подробности под катом.
Важно: Данное решение кросплатформенно, требует только STL и компилятора C++, который «умеет» шаблоны.
Вначале — синонимы типов — для того, чтобы в случае экспериментов — было проще менять.
Copy Source | Copy HTML
- typedef std::string TWString;
- typedef __int64 bigint;
-
- const double DBL_NULL = 0;
- const bigint INT_NULL = -1;
- const TWString STR_NULL = TWString();
Базовый класс, который и обеспечивает «вкусности»
Copy Source | Copy HTML
- struct BaseType
- {
- bool IsStored;
- enum BaseValueState {bvsStore, bvsSet, bvsGet, bvsErase};
- BaseType():IsStored(false)
- {
- }
- virtual ~BaseType()
- {
- if(IsStored)
- {
- int tempInt = int();
- double tempDbl = double();
- TWString tempStr = TWString();
- FieldStorage("", tempInt, bvsErase);
- FieldStorage("", tempStr, bvsErase);
- FieldStorage("", tempDbl, bvsErase);
- }
- }
- virtual void StoreValue() = 0;
-
- template <class T>
- void FieldStorage(const TWString & Tag, T& Value,
- BaseValueState State = bvsStore)
- {
- typedef std::map<void*, std::map<TWString , T*> > FieldMap;
- static FieldMap Values;
- static T Empty = T();
- if (!IsStored)
- IsStored = true;
- switch(State)
- {
- case bvsStore:
- Values[this][Tag] = &Value;
- break;
- case bvsSet:
- {
- T* Ptr = Values[this][Tag];
- if (Ptr)
- *Ptr = Value;
- }
- break;
- case bvsGet:
- {
- T* Ptr = Values[this][Tag];
- Value = (Ptr) ? *Ptr : Empty;
- }
- break;
- case bvsErase:
- Values.erase(this);
- break;
- }
- }
-
- template <typename T>
- void GetField(const TWString & Tag, T& Value)
- {
- FieldStorage(Tag, Value, bvsGet);
- }
-
- template <typename T>
- void SetField(const TWString & Tag, T& Value)
- {
- FieldStorage(Tag, Value, bvsSet);
- }
-
- template <typename T>
- T GetField(const TWString & Tag)
- {
- T Value;
- FieldStorage(Tag, Value, bvsGet);
- return Value;
- }
- };
А вот так вот мы от него наследуемся:
Copy Source | Copy HTML
- struct TUser : public BaseType
- {
- TUser(int AId = INT_NULL, const TWString &ALogin = STR_NULL, const double ASalary = DBL_NULL)
- : Id(AId), Login(ALogin), Salary(ASalary)
- {}
- bigint Id;
- TWString Login;
- double Salary;
- void StoreValue()
- {
- FieldStorage("Id", Id);
- FieldStorage("Login", Login);
- FieldStorage("Salary", Salary);
- }
- };