簡體   English   中英

C++ 宏/元程序在編譯時確定成員數

[英]C++ macro/metaprogram to determine number of members at compile time

我正在開發一個具有基於消息/異步代理類架構的應用程序。 將有幾十種不同的消息類型,每種都由 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 可以讓我完成這種類型的計算嗎?

正如其他人已經建議的那樣,您需要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;

不,C++ 中無法知道所有成員的名稱或實際存在多少成員。

您可以將所有類型存儲在您的類中的mpl::vector中,但隨后您將面臨如何將它們轉換為具有適當名稱的成員的問題(如果沒有一些宏hacky,您將無法實現)。

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

我沒有測試它,所以可能有錯誤。

有幾個答案只是說這是不可能的,如果你沒有鏈接到 magic_get 我會同意他們的。 但令我驚訝的是,magic_get 表明,在某些情況下它實際上是可能的。 這表明證明某事不可能比證明某事可能更難!

對您的問題的簡短回答是直接使用 magic_get 中的設施,而不是自己重新實現它們。 畢竟,即使查看預 Boost版本的代碼,也不清楚它是如何工作的。 在評論中的某一時刻,它提到了一些關於構造函數參數的東西; 我懷疑這是關鍵,因為可以計算常規函數的參數,所以它可能正在計算大括號初始化結構所需的參數數量。 這表明它可能僅適用於普通的舊結構,而不是具有您自己方法的對象。

盡管如此,我還是建議像其他人建議的那樣使用反射庫。 我經常推薦的一個好方法是 Google 的 protobuf 庫,它具有反射和序列化以及多語言支持。 但是,它僅適用於純數據對象(例如普通的舊結構,但帶有向量和字符串)。

普通結構不支持計數成員,但 boost::fusion 提供了一種聲明可計數和可迭代結構的好方法。

這樣的事情可能會讓你更接近:

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

如果您的類型尊重某些屬性“SimpleAggregate” ),您可以使用magic_get (現在是boost_pfr )(來自 C++14/C++17)。

所以你會有類似的東西:

class message_b
{
public;
  long long identifier;
  char foobar;
};

static_assert(boost::pfr::tuple_size<message_b>::value == 2);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM