重命名地图迭代器的第一个和第二个

时间:2009-09-30 19:04:59

标签: c++ stl map iterator

有没有办法重命名地图迭代器的第一个和第二个访问器函数。我知道他们有这些名称是因为代表键和值的底层对,但我希望迭代器更具可读性。我认为这可能是使用迭代器适配器,但我不知道如何实现它。

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

我的意思是:

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
}

8 个答案:

答案 0 :(得分:18)

如果您只关心可读性,可以这样做:

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;

答案 1 :(得分: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)

答案 2 :(得分:7)

不幸的是,没有。我通常做的是:

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

为了便于阅读。在你的循环内你也可以说

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

答案 3 :(得分:6)

当然,重新实现或包装迭代器,但值得努力吗?不会

Vertex& v = it->first;

更容易吗?

答案 4 :(得分: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;
}

答案 5 :(得分: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';
    }
}

这是我能做的最好的事情。我也尝试让这些仿函数直接接受迭代器,但这种或那种方式意味着签名将包含依赖名称,这显然使模板类型推断不可能(我找不到为iterator/const_iterator重载GetSecond的方法即使延迟返回类型为C ++ 0x)。

答案 6 :(得分:0)

我有一个邪恶的解决方案!

#define vertex first
#define edge second

虽然作为一种邪恶的解决方案,但是当你不小心在其他地方使用这些词时,它无疑会造成巨大的创伤并难以诊断编译问题。

添加完整性。

无法相信其他人没有这样做过。

答案 7 :(得分:0)

如果您不需要迭代器(例如,基于范围的for循环适合您的目的),那么从 c ++ 17 开始,您可以使用结构化绑定

map<Vertex, Edge> adjacency_list;
for( auto & [ vertex, edge ] : adjacency_list )
{
    // do stuff with vertex
}