C ++宏/元程序,用于确定编译时的成员数

时间:2011-07-27 12:52:43

标签: c++ macros metaprogramming

我正在使用基于消息/异步代理的架构的应用程序。 将会有几十种不同的消息类型,每种类型都由C ++类型表示。

class message_a
{
  long long identifier;
  double some_value;
  class something_else;
  ...//many more data members
}

是否可以编写一个宏/元程序,允许在编译时计算类中数据成员的数量?

//例如:

class message_b
{
  long long identifier;
  char foobar;
}


bitset<message_b::count_members> thebits;

我不熟悉C ++元编程,但是boost :: mpl :: vector可以让我完成这种类型的计算吗?

5 个答案:

答案 0 :(得分:4)

正如其他人已经建议的那样,您需要Boost.Fusion及其BOOST_FUSION_DEFINE_STRUCT。您需要使用未使用但非常简单的语法来定义结构。因此,您会收到必需的count_members(通常命名为size),而且灵活性远远超过此范围。

您的示例:

定义:

BOOST_FUSION_DEFINE_STRUCT(
    (), message_a,
    (long long, identifier),
    (double, some_value)
)

用法:

message_a a;
size_t count_members = message_a::size;

答案 1 :(得分:3)

不,C ++中没有办法知道所有成员的名字或者实际上有多少成员。

你可以将所有类型存储在类中的mpl::vector中,但是你会面临如何将它们变成具有适当名称的成员的问题(如果没有一些宏的hackery你就无法实现)。

使用std::tuple而不是POD是一种解决方案,通常可以工作,但是当您实际使用元组(没有命名变量)时会产生令人难以置信的混乱代码,除非您在某个时候转换它或者有一个转发访问器的包装器到元组成员。

class message {
public:
  // ctors
  const int& foo() const { return std::get<0>(data); }
  // continue boiler plate with const overloads etc

  static std::size_t nun_members() { return std::tuple_size<data>::value; }
private:
  std::tuple<int, long long, foo> data;
};

Boost.PP和MPL的解决方案:

#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>

struct Foo {
  typedef boost::mpl::vector<int, double, long long> types;

// corresponding type names here
#define SEQ (foo)(bar)(baz)
#define MACRO(r, data, i, elem) boost::mpl::at< types, boost::mpl::int_<i> >::type elem;
BOOST_PP_SEQ_FOR_EACH_I(MACRO, 0, SEQ)

};

int main() {
  Foo a;
  a.foo;
}

我没有测试它,所以可能存在错误。

答案 2 :(得分:0)

普通结构不支持计数成员,但boost :: fusion提供了一种声明计数和迭代结构的好方法。

答案 3 :(得分:0)

这样的事情可能会让你更接近:

struct Foo {
    Foo() : a(boost::get<0>(values)), b(boost::get<1>(values)) {}
    int &a;
    float &b;
    typedef boost::tuple<int,float> values_t;
    values_t values;
};

答案 4 :(得分:0)

有几个答案简单地说这是不可能的,如果你没有链接到magic_get,我会同意他们。但令我惊讶的是,magic_get显示在某些情况下它实际上是可能的。这表明证明某事不可能比证明某事是可能的更难!

你的问题的简短答案是直接使用magic_get中的设施,而不是自己重新实现它们。毕竟,即使查看代码的pre-Boost版本,也不清楚它是如何工作的。在评论中的某一点,它提到了关于构造函数参数的一些内容;我怀疑这是关键,因为it is possible to count the arguments to a regular function,所以也许它正在计算支持初始化结构所需的参数数量。这表明它只能用普通的旧结构而不是用你自己的方法的对象。

尽管如此,我建议使用其他人建议的反射库。我经常推荐的一个好的是Google的protobuf库,它具有反射和序列化以及多语言支持。但是,它仅适用于纯数据对象(如普通的旧结构,但带有向量和字符串)。