Доступ к членам в структуре C ++ как динамически, так и статически - PullRequest
6 голосов
/ 02 декабря 2010

Я хотел бы иметь структуру (или что-то подобное) в C ++, которая позволит динамически получать доступ к ее членам. Он должен иметь общий метод получения и установки, которые получают имя члена в виде строки и возвращают какой-либо вариантный тип (например, boost::variant).

Я думал, что это можно реализовать, используя boost::fusion::map, добавив строку, представляющую имя каждого члена, и построив карту STL между строками и функциями получения или установки. Я не хочу изобретать велосипед, поэтому я надеялся, что нечто подобное уже существовало.

Что ты думаешь? Будет ли моя идея работать? Вы знаете другие способы достижения моей цели?

Спасибо, Аггей

Ответы [ 3 ]

6 голосов
/ 02 декабря 2010

fusion - это подход, но почему бы не сохранить ваши «поля» в std::map, обозначенном std::string, где полезной нагрузкой является boost::variant ...

т.е.

struct generic
{
std::map<std::string, boost::variant<foo, bar, bob, int, double> > _impl;
};

и тогда вы можете просто найти ключ в вашем геттере / установщике ...

черт возьми, оберните variant в optional, и вы можете иметь дополнительные поля!

более сложный пример:

class foo
{
public:
  typedef boost::variant<int, double, float, string> f_t;
  typedef boost::optional<f_t&> return_value;
  typedef map<string, return_value> ref_map_t;

  foo() : f1(int()), f2(double()), f3(float()), f4(string()), f5(int()) 
  {
    // save the references..
    _refs["f1"] = return_value(f1);
    _refs["f2"] = return_value(f2);
    _refs["f3"] = return_value(f3);
    _refs["f4"] = return_value(f4);
    _refs["f5"] = return_value(f5);
  }

  int getf1() const { return boost::get<int>(f1); }
  double getf2() const { return boost::get<double>(f2); }
  float getf3() const { return boost::get<float>(f3); }
  string const& getf4() const { return boost::get<string>(f4); }
  int getf5() const { return boost::get<int>(f5); }

  // and setters..
  void setf1(int v) { f1 = v; }
  void setf2(double v) { f2 = v; }
  void setf3(float v) { f3 = v; }
  void setf4(std::string const& v) { f4 = v; }
  void setf5(int v) { f5 = v; }

  // key based
  return_value get(string const& key)
  {
    ref_map_t::iterator it = _refs.find(key);
    if (it != _refs.end())
      return it->second;
    return return_value();
  }

  template <typename VT>
  void set(string const& key, VT const& v)
  {
    ref_map_t::iterator it = _refs.find(key);
    if (it != _refs.end())
      *(it->second) = v;
  }

private:
  f_t f1;
  f_t f2;
  f_t f3;
  f_t f4;
  f_t f5;

  ref_map_t _refs;
};

int main(void)
{
  foo fancy;
  fancy.setf1(1);
  cout << "f1: " << fancy.getf1() << endl;

  fancy.set("f1", 10);
  cout << "f1: " << fancy.getf1() << endl;

  return 0;
}
1 голос
/ 02 декабря 2010

То, что я сделал для этого, было расширенным :: cons-подобным списком типов, который содержит моих участников и какое-то описание.Затем я строю это отображение, последовательно добавляя своих членов в структуру данных «мета-информация» с помощью «связанных» вызовов функций.Все это выглядит очень похоже на определение класса в boost.python.Если вы действительно используете boost :: cons, он также должен работать как последовательность в boost.fusion, так что вы можете легко перебирать свои данные.Возможно, вы можете использовать карту boost.fusion вместо этого, чтобы получить время доступа к log (n) во время выполнения, но кажется, что их размер ограничен до тех пор, пока не появятся различные шаблоны.

1 голос
/ 02 декабря 2010

Вы запрашиваете Отражение в C ++, которое, я думаю, недоступно.Вам придется придумать что-то свое.

...