访问 C++ 中的成员动态和静态结构

发布于 2024-10-06 07:55:41 字数 281 浏览 10 评论 0原文

我想在 C++ 中有一个结构(或类似的东西),它允许动态访问其成员。它应该有一个通用的 getter 和 setter,以字符串形式接收成员名称,并返回某种变体类型(例如 boost::variant)。

我认为它可以使用 boost::fusion::map 来实现,通过添加一个表示每个成员名称的字符串,并在字符串和 getter 或 setter 函数之间构建 STL 映射。我不想重新发明轮子,所以我希望类似的东西已经存在。

你怎么认为?我的想法可行吗?您知道实现我的目标的其他方法吗?

I would like to have a struct (or something similar) in C++, that will allow access to its members dynamically. It should have a generic getter and setters that receive the member name as a string, and return some sort of variant type (e.g. boost::variant).

I was thinking it could be implemented using boost::fusion::map, by adding a string representing the name of each member, and building an STL map between strings and getter or setter functions. I don't want to reinvent the wheel, so I was hoping something similar already existed.

What do you think? Would my idea work? Do you know other ways to accomplish my goal?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

fusion 是一种方法,但为什么不将您的“字段”存储在由 std::string 键控的 std::map 中,其中有效负载是 boost ::variant...

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

然后你可以在 getter/setter 中查找键...

哎呀,将 variant 包装在 可选 中,然后你可以有可选字段!

一个更复杂的例子:

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;
}

fusion is an approach, but why not store your "fields" in a std::map keyed by a std::string, where the payload is the boost::variant...

i.e.

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

and then you can just lookup the key in your getter/setter...

heck, wrap the variant in an optional and you could have optional fields!

a more complex example:

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;
}
邮友 2024-10-13 07:55:41

您正在要求 C++ 中的Reflection,我认为这是不可用的。你必须想出一些你自己的东西。

You are asking for Reflection in C++ which I think is not available. You will have to come up with something of your own.

梦在深巷 2024-10-13 07:55:41

我为此所做的是一个类似于 boost::cons 的类型列表,其中包含我的成员和某种描述。然后,我通过“链接”函数调用将我的成员连续添加到“元信息”数据结构中来构建此映射。整个事情看起来与在 boost.python 中定义一个类非常相似。如果您实际使用 boost::cons,它也应该作为 boost.fusion 中的序列工作,这样您就可以很好地迭代数据。也许您可以使用 boost.fusion 映射来在运行时获取 log(n) 访问时间,但在可变参数模板可用之前,它们的大小似乎受到限制。

What I did for this was a boost::cons-like type-list that contains my members and some kind of description. I then build this mapping by successively adding my members to a "meta-info" data structure by "chained" function calls. The whole thing looks very similar to defining a class in boost.python. If you actually use boost::cons, it should also work as a sequence in boost.fusion, so you can iterate nicely over your data. Maybe you can use a boost.fusion map instead to get log(n) access times at run-time, but it seems their size is limited until variadic templates are available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文