2009-09-30 77 views
16

是否有任何方法來重命名映射迭代器的第一個和第二個訪問器函數?我明白他們有這些名字是因爲底層對代表了關鍵和價值,但我希望迭代器更具可讀性。我認爲這可能使用迭代器適配器,但我不知道如何實現它。重命名映射迭代器的第一個和第二個

請注意,我不能使用提升。

我的意思舉例:

map<Vertex, Edge> adjacency_list; 
for(map<Vertex, Edge>::iterator it = adjacency_list.begin(); 
    it != adjacency_list.end(); 
    ++it) 
{ 
    Vertex v = it->first; 
    //instead I would like to have it->vertex 
} 
+1

好玩:目前似乎有很多與圖形相關的問題:http://stackoverflow.com/questions/1499878/use-a-graph-library-node-network-library-or-roll-my-自己,http://stackoverflow.com/questions/1499217/boost-graph-as-basis-for-a-simple-dag-graph – 2009-09-30 19:17:02

+0

爲什麼你不能使用提升? – 2009-10-02 18:58:34

回答

15

如果你只是關心可讀性,你可以做這樣的事情:

typedef map<Vertex, Edge> AdjacencyList; 
struct adjacency 
{ 
    adjacency(AdjacencyList::iterator& it) 
     : vertex(it->first), edge(it->second) {} 
    Vertex& vertex; 
    Edge& edge; 
}; 

然後:

Vertex v = adjacency(it).vertex; 
5

當然,重新實現或包裹迭代器,但它是值得的?不會

Vertex& v = it->first; 

更簡單嗎?

+3

還要記住,使用std :: map迭代器的第一個和第二個是這樣一個常見的習慣用法,你會讓任何讀取你的代碼的人感到困惑 - 有點。 – phoku 2009-09-30 19:12:55

+3

這是真的,但從理性的角度來看,'first'和'second'已經讓人困惑了;-) – 2009-09-30 19:14:24

7

不幸的是,沒有。我通常做的是這樣的:

typedef map<Vertex, Edge> AdjacencyList; 
typedef AdjacencyList::value_type Vertex_Edge_Pair; 

爲了便於閱讀,裏面你的循環,你也可以說

Vertex& current_vertex = it->first; 
Edge& current_edge = it->second; 
12

你不能重命名成員,但你可以有一些功能來幫助。

inline Vertex& vertex(map<Vertex, Edge>::iterator& it) {return it->first;} 
inline Edge& edge(map<Vertex, Edge>::iterator& it) {return it->second;} 

然後,而不是it->vertex像你想,你可以做vertex(it)

+1

+1還爲const_iterators添加重載。 – UncleBens 2009-09-30 21:27:48

1

我不會推薦使用真本,但它似乎工作,至少要測試程序的最小程度做我想要的/預計:

#include <map> 
#include <string> 
#include <iostream> 

template <class T, class U> 
struct my_pair : public std::pair<T, U> { 
    T const &vertex; 
    my_pair(std::pair<T, U> const &x) : std::pair<T, U>(x), vertex(x.first) { } 
}; 

template <class T, class U> 
struct my_map : public std::map<T, U> { 
    my_pair<T, U> find(T const &t) { return my_pair<T, U>(*std::map<T,U>::find(t)); } 
}; 

class Vertex { 
    int x; 
public: 
    Vertex(int v) : x(v) {} 
    bool operator<(Vertex const &other) const { return x < other.x; } 
    friend std::ostream &operator<<(std::ostream &os, Vertex const &v) { return os << v.x; } 
}; 

int main() { 
    my_map<Vertex, std::string> m; 

    m[1] = "This is it"; 

    my_pair<Vertex, std::string> mp = m.find(1); 
    std::cout << mp.vertex << ": " << mp.second; 
    return 0; 
} 
1

我喜歡KeithB的解決方案與免費功能。但是,更可重用的解決方案可能會更好。

什麼訪問的第一或第二,你可以命名實例任何你喜歡的函數對象:

#include <map> 
#include <string> 
#include <iostream> 

struct GetFirst 
{ 
    template <class First, class Second> 
    First& operator()(std::pair<First, Second>& p) 
    { 
     return p.first; 
    } 

    template <class First, class Second> 
    const First& operator()(const std::pair<First, Second>& p) 
    { 
     return p.first; 
    } 
}; 

struct GetSecond 
{ 
    template <class First, class Second> 
    Second& operator()(std::pair<First, Second>& p) 
    { 
     return p.second; 
    } 

    template <class First, class Second> 
    const Second& operator()(const std::pair<First, Second>& p) 
    { 
     return p.second; 
    } 
}; 

int main() 
{ 
    typedef std::map<std::string, int> Map; 

    Map persons; 
    persons["John"] = 20; 
    persons["Mary"] = 24; 

    //create named accessors 
    GetFirst name; 
    GetSecond age; 

    for (Map::iterator it = persons.begin(); it != persons.end(); ++it) { 
     std::cout << name(*it) << " is aging.\n"; 
     ++age(*it); 
    } 

    for (Map::const_iterator it = persons.begin(); it != persons.end(); ++it) { 
     std::cout << "Name: " << name(*it) << ", age: " << age(*it) << '\n'; 
    } 
} 

這是我能做到的最好。我也嘗試讓這些函子直接接受迭代器,但這樣或那樣的這意味着該簽名將包含依賴名稱,這顯然使模板類型推演不可能(我無法找到一種方法來重載GetSecond的iterator/const_iterator即使延遲返回類型的C++ 0x)。

0

我有一個邪惡的解決方案!

#define vertex first 
#define edge second 

雖然作爲一個邪惡的解決方案。它無疑將造成巨大的創傷和難以診斷編譯的問題,當你不小心使用這些詞在其他地方。

爲了完整而增加。

不能相信別人沒有提出這個建議。

+0

沒有人建議這是因爲這是一個可怕的想法。 – user1353535 2017-08-25 16:00:46

相關問題