2009-09-10 70 views
12

我想創建一個std::map包含迭代器本身的std::vector,實現一個簡單的基於列表的鄰接圖結構。STL地圖本身?

然而,類型聲明有我難住了:這似乎需要整個地圖類型定義,以獲得迭代器類型的表示圖,就像這樣:

map< int, Something >::iterator MyMap_it; // what should Something be? 
map< int, vector<MyMap_it> > MyMap_t; 

是否有某種形式的部分地圖迭代我只能使用鍵類型獲得類型,所以我可以聲明完整的地圖?

+2

Interesting..sounds像無限遞歸。 – Naveen 2009-09-10 05:32:57

+0

這就是我的想法。 – GManNickG 2009-09-10 05:38:42

+1

只是一個循環指針......除非map <> :: iterator試圖用它的類型參數做一些有意義的事情,否則不會有遞歸。這對於它來說是完全合法的,只是在GCC + SGI STL中不會發生。 – Potatoswatter 2009-09-10 07:05:26

回答

14

您可以使用新類型的前向聲明。

class MapItContainers; 
typedef map<int, MapItContainers>::iterator MyMap_it; 

class MapItContainers 
{ 
public: 
vector<MyMap_it> vec; 
}; 

有了這種間接方式,編譯器應該讓你脫身。 這不是很漂亮,但老實說,我不認爲你可以輕鬆地打破自我引用。

+0

gcc 4.4.1看起來不是在這個barf,它甚至讓我創建'map '的實例。 – Omnifarious 2009-09-10 06:07:10

+0

可能因爲迭代器只使用指向第二個模板參數類型的指針/引用,所以前向聲明就足夠了。 – Kos 2011-12-20 01:10:49

5

不太醜,考慮...

這個工作在GCC 4.0.1和科莫嚴格模式編譯罰款。

模板定義進行分析和推遲,直到他們被實例化。編譯器甚至沒有看到rec_map_iterator是什麼時候才創建一個,直到它知道如何去做; v)。

template< class key > 
struct rec_map; 

template< class key > 
struct rec_map_iterator : rec_map<key>::iterator { 
    rec_map_iterator(typename rec_map<key>::iterator i) 
    : rec_map<key>::iterator(i) {} 
}; 

template< class key > 
struct rec_map : map< key, vector< rec_map_iterator<key> > > {}; 

這是我所使用的測試程序。

#include <iostream> 
#include <map> 
#include <vector> 

using namespace std; 

template< class key > 
struct rec_map; 

template< class key > 
struct rec_map_iterator : rec_map<key>::iterator { 
    rec_map_iterator(typename rec_map<key>::iterator i) 
    : rec_map<key>::iterator(i) {} 
}; 

template< class key > 
struct rec_map : map< key, vector< rec_map_iterator<key> > > {}; 

int main(int argc, char ** argv) { 
    rec_map<int> my_map; 

    my_map[4]; 
    my_map[6].push_back(my_map.begin()); 

    cerr << my_map[6].front()->first << endl; 

    return 0; 
} 
+0

+1令我害怕。儘管如此,我不會在生產代碼中使用它,但nasmorns解決方案要簡單得多。 – hirschhornsalz 2009-09-10 07:24:11

+0

我可以讓你編寫更簡單的代碼,除了一次性的詭計。也許不那麼優雅,但我認爲它更符合C++的精神; v)。 – Potatoswatter 2009-09-10 07:32:27

+0

爲什麼模板 struct rec_map_iterator:rec_map :: iterator'需要在'rec_map :: iterator'前面加上'typename'?基本初始化列表也是如此。 (FWIW,科莫同意你的GCC,但我不明白爲什麼會這樣)。 – sbi 2009-09-10 08:37:44

2

我不喜歡在我以前的答案從容器中派生所以這裏的一種替代方案:

template< class key > 
struct rec_map_gen { 
    struct i; 
    typedef map< key, vector<i> > t; 
    struct i : t::iterator { 
     i(typename t::iterator v) 
     : t::iterator(v) {} 
    }; 
}; 

現在你必須使用rec_map_gen<int>::trec_map_gen<int>::t::iterator,等等,但你也可以訪問所有std::map的構造函數。這太糟糕了,C++不允許typedefs模板化。

使用派生迭代器類型應該沒問題。例如,您仍然可以從此結構的元素初始化反向迭代器。

2

除了Potatoswatter的答案,如果你不介意指整個模板地圖類型多次,你只需要繼承迭代器,不需要任何預先聲明:

template<class key> 
struct rec_map_iterator : map<key, vector<rec_map_iterator<key> > >::iterator 
{ 
    rec_map_iterator(typename map<key, vector<rec_map_iterator<key> > >::iterator i) 
     : map<key, vector<rec_map_iterator<key> > >::iterator(i) 
    {} 
}; 
通過聲明rec_map作爲一個別名,它可以作爲模板

map<int, vector<rec_map_iterator<int>>> m; 

而且,這裏是一個更新(我的最愛到目前爲止)對C++ 11:

然後使用完整的類型3210

這個工程一樣Potatoswatter的版本:

rec_map<int> my_map; 
+0

這是類似於我*第二*答案:)但C++ 11因子更好。 – Potatoswatter 2017-01-30 13:34:28