2012-05-12 101 views
0

我想創建一個類似於列表的東西。但是,列表的不同實例可能具有不同數量的條目,並且條目的類型基於用戶給出的輸入。例如,用戶聲明他們希望列表中每個條目的結構都包含一個int id,一個std :: string名稱,一個雙重度量標準A和一個長度量標準B.基於此輸入,創建以下:具有可變大小和可變類型的C++容器

struct some_struct { 
    int id; 
    std::string name; 
    double metricA; 
    long metricB; 
} 

list<some_struct> some_list; 

用戶輸入可以從文件中讀取,在屏幕上輸入,等等。另外,它們在some_struct條目的數目可變。換句話說,它可能有上面列出的條目,它可能只有2個,或者可能有10個完全不同的條目。有沒有辦法像這樣創建一個結構?

此外,能夠將比較運算符應用於some_struct的每個成員是必須的。我可以使用boost :: any來存儲數據,但這會造成比較運算符的問題,並且還會產生比理想更多的開銷。

+0

我不清楚爲什麼「條目數」是一個問題,因爲列表不是固定的大小。 –

+0

我只說過,因爲有人可能會推薦不使用列表並且只支持固定大小條目數的解決方案。 – user396404

+0

假設您可以創建這樣的數據結構。你會做什麼?你能用C++來展示一些預期用法的例子 - 就像僞代碼一樣嗎? –

回答

0

我最終使用了boost :: variant類型的列表。性能比使用boost :: any要好得多。它是這樣的:

#include <boost/variant/variant.hpp> 
#include <list> 

typedef boost::variant< short, int, long, long long, double, string > flex; 
typedef pair<string, flex> flex_pair; 
typedef list<flex_pair> row_entry; 

list<row_entry> all_records; 
4

C++是一種強類型語言,這意味着您必須聲明您的數據結構類型。爲此,您不能用任意數量或類型的成員聲明struct,他們必須事先知道。

現在有很多方法可以解決C++中的這些問題。僅舉幾例:

  • 使用地圖(無論是std::mapstd::unordered_map)創建一個「表」,而不是一個結構。將字符串映射到字符串,即將名稱映射到值的字符串表示形式,並將它們解釋爲您的心臟。
  • 使用預製罐頭變體類型,如boost::any
  • 使用多態性 - 將指針存儲在列表中,並在值上調用虛擬機制調度操作。
  • 創建一個類型系統爲您的輸入語言。然後有每個類型的值表,並從列表中指向適當的表。

有很多其他的方法可以做到這一點,因爲有C++程序員。

2

有很多方法可以解決不同成員的數據結構問題,最好的方法很大程度上取決於它將如何使用。

最明顯的是使用繼承。你獲得從基類的所有可能性:

struct base_struct { 
    int id; 
    std::string name; 
}; 

list<base_struct*> some_list; 

struct some_struct : public base_struct { 
    double metricA; 
}; 


struct some_other_struct : public base_struct { 
    int metricB; 
}; 

base_struct *s1 = new some_struct; 
s1->id = 1; 
// etc 

base_struct *s2 = new some__other_struct; 
s2->id = 2; 
// etc 

some_list.push_back(s1); 
some_list.push_back(s2); 

棘手的一點是,你必須確保當你回來的元素了,你的情況下適當。使用type_info鑄造前

some_struct* ss = dynamic_cast<some_struct*>(some_list.front()); 

您可以查詢名稱:dynamic_cast可以在一個類型安全的方式做到這一點

typeid(*some_list.front()).name(); 

注意,這兩種需要與RTTI,這通常是OK的建設,但並非總是如RTTI具有性能成本,並且可能膨脹你的內存佔用,特別是如果廣泛使用模板。

在之前的項目中,我們使用boost any來處理類似的事情。 any的優點是它允許你混合不相互派生的類型。回想起來,我不確定我會再這樣做,因爲它使得代碼在運行時過於容易失敗,因爲類型檢查正在推遲到那時。 (這是dynamic_cast的做法也是如此

在壞舊的C日子裏,我們解決了一個union此相同的問題:同樣

struct base_struct { 
    int id; 
    std::string name; 
    union { // metricA and metricB share memory and only one is ever valid 
     double metricA; 
     int metricB; 
    }; 
}; 

,你有,你必須處理的問題確保它是你自己的正確類型

在STL之前的時代,許多容器系統被編寫爲採用void*,同樣需要用戶知道什麼時候需要施放。理論上,你仍然可以通過說list<void*>但您無法查詢該類型。

編輯:從來沒有,有史以來使用void*方法!