簡體   English   中英

通過變量名迭代struct

[英]Iterate through struct by variable name

更新:6個月后,我剛剛遇到了這樣的答案: 索引結構是否合法?:Slava回答 我認為這是一個比這里提供的更好的解決方案,因為絕對沒有未定義的行為。 希望這對下一個人有所幫助,因為對我來說已經太晚了。


在您發表評論告訴我使用數組或向量或任何形式的容器之前,這是一個我不能做的事實。 我知道,這將通過數組來解決,否則任何解決方案都非常“hacky”。 我很想用一個容器,但我絕對不能。

我是一家非常大的公司的中級開發人員,我們正在使用公司范圍的庫來通過以太網發送數據。 有多種原因可以解釋為什么它不能支持數組/向量,而是使用POD結構(普通舊數據 - 字符,浮點數,整數,粗體)。 我從一個浮點數開始,我必須使用它來填充具有相同浮點數的結構。 由於這個庫的目的是通過以太網發送消息,我只需要進行兩次迭代 - 一次在發送上,一次在接收上。 所有其他時間,此數據存儲為數組。 我知道 - 我應該將數組序列化並按原樣發送,但我再說一遍 - 我絕對不能。

我有一個float[1024] ,並且必須遍歷數組並填充以下結構:

struct pseudovector
{
    float data1;
    float data2;
    float data3;
    ...
    float data1024;
}

我已經使用BOOST_PP_REPEATBOOST_PP_SEQ_FOR_EACH_I生成了這個結構,這樣我就不必寫出所有1024個浮點數,並且它增加了可維護性/可擴展性。

以同樣的方式,我嘗試通過預編譯器## concatination( https://stackoverflow.com/a/29020943/2066079 )迭代結構,但由於這是在預編譯時完成的,因此無法使用用於運行時獲取/設置。

我已經研究過如何實現反射,例如如何向C ++應用程序添加反射? Ponder Library ,但這兩種方法都要求您明確寫出可以反映的每個項目。 在這種情況下,我不妨創建一個std::map<string, float>並通過字符串/整數連接在for循環中迭代:

for(i=0;i<1024;i++)
{
    array[i] = map.get(std::string("data")+(i+1))
}

任何人都可以推薦一個更清潔的解決方案,不需要我寫出超過1024行代碼? 非常感謝您的幫助!

我再說一遍 - 我絕對不能使用任何類型的數組/向量。

這可能比您預期的要容易。 首先,一些警告:

  1. 按標准,陣列保證是連續的; 也就是說,它們之間沒有插入填充,並且數組本身與元素類型的對齊要求對齊。

  2. 結構沒有這樣的限制; 它們可以受到任意填充。 但是,給定的實現(在給定版本中)將在所有翻譯單元中以相同的方式執行此操作(否則,如何使用相同的結構定義來跨翻譯單元傳遞數據?)。 通常的方法是相當理智,特別是當struct 包含單個類型的成員時。 對於這樣的結構,對齊通常匹配成員的最大對齊,並且通常沒有填充,因為所有成員具有相同的對齊。

在你的情況下,1024個浮點數的數組和1024個浮點數的結構幾乎肯定具有完全相同的內存布局。 標准絕對不能保證這一點,但您的編譯器可能會記錄其結構布局規則,並且您始終可以在單元測試中斷言大小和對齊匹配(您確實有單元測試,對吧?)

鑒於這些警告,您幾乎肯定能夠簡單地在兩者之間reinterpret_cast (或memcpy )。

您可以使用類型punning將結構視為數組。

float array[1024] = { ... };
pseudovector pv1;
float *f = static_cast<float*>(static_cast<void*>(&pv1));
for (int i = 0; i < 1024; i++) {
    f[i] = array[i];
}

您可以使用預處理器元編程來創建數組。 你可以這樣做:

#define ACCESSOR(z, n, type) &type::data ## n

auto arr[] = {
    BOOST_PP_ENUM(1000, ACCESSOR, pseudovector)
};

最有可能需要調整ACCESSOR。 在這里使用auto可能也不合法。

然后你做:

auto val = (pv1.*arr)[4];

等等...

不需要UB。

使用Boost.Hana ,如果你可以用最新版本的Clang或GCC編譯(afaik,唯一支持的編譯器。)

請允許我引用教程中的Introspection部分:

正如我們將在此討論的那樣,靜態內省是程序在編譯時檢查對象類型的能力。 換句話說,它是一個在編譯時與類型交互的編程接口。 例如,你有沒有想過檢查一些未知類型是否有一個名為foo的成員? 或者在某些時候你需要迭代結構的成員?

對於內省用戶定義的類型,您必須使用Hana定義結構,但這與定義結構沒有太大區別:

struct pseudovector {
   BOOST_HANA_DEFINE_STRUCT(pseudovector,
    (float, data1),
    (float, data2),
    …
  );
};

您應該可以輕松地修改生成當前結構的任何宏,以生成此結構。

這為pseudovector添加了一個嵌套結構,它只包含一個靜態成員函數。 它不會影響POD,大小或數據布局。

然后你可以像在這個例子中一樣迭代它:

pseudovector pv;

hana::for_each(pv, [](auto pair) {
  std::cout << hana::to<char const*>(hana::first(pair)) << ": "
            << hana::second(pair) << std::endl;
});

這里, pair的成員是hana編譯時字符串(成員名稱)和值。 如果你想讓你的lambda采用兩個參數(名稱和值),請使用hana::fuse

hana::for_each(pv, hana::fuse([](auto name, auto member) {
  std::cout << hana::to<char const*>(name) << ": " << member << std::endl;
}));

暫無
暫無

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

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