Pull to refresh

C++ и reflection на коленке

Reading time6 min
Views916
Потребовалось тут недавно иметь возможность обращаться к полю в структуре по её имени — записать, прочитать значение. И так, чтобы производительность тех мест, где это не используется не изменилась.
Вот что получилось:
Copy Source | Copy HTML
  1. TUser user;
  2. user.StoreValue();
  3. double SalaryRef;
  4. user.SetField("Salary", SalaryRef); // сохранили 
  5. user.GetField("Salary", SalaryRef); // загрузили - передача по ссылке
  6.  
  7. // можно ещё и так, но сами понимаете - не удобно
  8. double Salary = user.GetField<double>("Salary");


Весь секрет в «волшебных пузырьках» — в классе от которого наследуется TUser, и одной функции — StoreValue().
Подробности под катом.

Важно: Данное решение кросплатформенно, требует только STL и компилятора C++, который «умеет» шаблоны.


Вначале — синонимы типов — для того, чтобы в случае экспериментов — было проще менять.

Copy Source | Copy HTML
  1. typedef std::string TWString;
  2. typedef __int64 bigint;
  3.  
  4. const double DBL_NULL =  0;
  5. const bigint INT_NULL = -1;
  6. const TWString STR_NULL = TWString();


Базовый класс, который и обеспечивает «вкусности»
Copy Source | Copy HTML
  1. struct BaseType
  2. {
  3.     bool IsStored;
  4.     enum BaseValueState {bvsStore, bvsSet, bvsGet, bvsErase};
  5.     BaseType():IsStored(false)
  6.     {
  7.     }
  8.     virtual ~BaseType()
  9.     {
  10.         if(IsStored)
  11.         {
  12.             int tempInt = int();
  13.             double tempDbl = double();
  14.             TWString tempStr = TWString();
  15.             FieldStorage("", tempInt, bvsErase);
  16.             FieldStorage("", tempStr, bvsErase);
  17.             FieldStorage("", tempDbl, bvsErase);
  18.         }
  19.     }
  20.     virtual void StoreValue() =  0;
  21.  
  22.     template <class T>
  23.         void FieldStorage(const TWString & Tag, T& Value,
  24.                                 BaseValueState State = bvsStore)
  25.         {
  26.             typedef std::map<void*, std::map<TWString , T*> > FieldMap;
  27.             static FieldMap Values;
  28.             static T Empty = T();
  29.             if (!IsStored)
  30.                 IsStored = true;
  31.             switch(State)
  32.             {
  33.                 case bvsStore:
  34.                     Values[this][Tag] = &Value;
  35.                     break;
  36.                 case bvsSet:
  37.                     {
  38.                         T* Ptr = Values[this][Tag];
  39.                         if (Ptr)
  40.                             *Ptr = Value;
  41.                     }
  42.                     break;
  43.                 case bvsGet:
  44.                     {
  45.                         T* Ptr = Values[this][Tag];
  46.                         Value = (Ptr) ? *Ptr : Empty;
  47.                     }
  48.                     break;
  49.                 case bvsErase:
  50.                     Values.erase(this);
  51.                     break;
  52.             }
  53.         }
  54.  
  55.     template <typename T>
  56.         void GetField(const TWString & Tag, T& Value)
  57.         {
  58.             FieldStorage(Tag, Value, bvsGet);
  59.         }
  60.  
  61.     template <typename T>
  62.         void SetField(const TWString & Tag, T& Value)
  63.         {
  64.             FieldStorage(Tag, Value, bvsSet);
  65.         }
  66.  
  67.     template <typename T>
  68.         T GetField(const TWString & Tag)
  69.         {
  70.             T Value;
  71.             FieldStorage(Tag, Value, bvsGet);
  72.             return Value;
  73.         }
  74. };


А вот так вот мы от него наследуемся:
Copy Source | Copy HTML
  1. struct TUser : public BaseType
  2. {
  3.     TUser(int AId = INT_NULL, const TWString &ALogin = STR_NULL, const double ASalary = DBL_NULL)
  4.         : Id(AId), Login(ALogin), Salary(ASalary)
  5.     {}
  6.     bigint Id;
  7.     TWString Login;
  8.     double Salary;
  9.     void StoreValue()
  10.     {
  11.         FieldStorage("Id", Id);
  12.         FieldStorage("Login", Login);
  13.         FieldStorage("Salary", Salary);
  14.     }
  15. };
Tags:
Hubs:
Total votes 17: ↑8 and ↓9-1
Comments30

Articles