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

发布于 2024-08-06 11:06:20 字数 400 浏览 1 评论 0原文

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

请注意,我无法使用 boost。

我的意思的例子:

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
}

Is there any way to rename the first and second accessor functions of a map iterator. I understand they have these names because of the underlying pair which represents the key and value, but I'd like the iterators to be a little more readable. I think this might be possible using an iterator adaptor, but I'm not sure how to implement it.

Please note that I can't use boost.

Example of what I mean:

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

夜吻♂芭芘 2024-08-13 11:06:20

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

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;

If you're just concerned about readability you could do something like this:

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

And then:

Vertex v = adjacency(it).vertex;
抽个烟儿 2024-08-13 11:06:20

您无法重命名成员,但可以使用一些功能来提供帮助。

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

然后,您可以执行 vertex(it) ,而不是像您想要的那样 it->vertex

You can't rename the members, but you can have some functions to help.

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

Then, instead of it->vertex like you want, you can do vertex(it)

甜点 2024-08-13 11:06:20

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

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

If you don't need the iterator (e.g., a range-based for loop suits your purpose), then as of c++17 you can use structured bindings:

map<Vertex, Edge> adjacency_list;
for( auto & [ vertex, edge ] : adjacency_list )
{
    // do stuff with vertex
}
划一舟意中人 2024-08-13 11:06:20

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

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

为了可读性。在你的循环中你也可以说

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

Unfortunately, no. What I usually do is this:

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

For readability. Inside your loop you can also say

Vertex& current_vertex = it->first;
Edge& current_edge = it->second;
半寸时光 2024-08-13 11:06:20

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

Vertex& v = it->first;

更容易吗?

Sure, reimplement or wrap iterator, but is it worth the effort? Wouldn't

Vertex& v = it->first;

be easier?

月亮是我掰弯的 2024-08-13 11:06:20

我不建议真正使用它,但它似乎确实有效,至少在测试程序执行我想要/期望的事情的最低程度上:

#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;
}

I wouldn't recommend really using this, but it does seem to work, at least to the minimum degree of the test program doing what I wanted/expected:

#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;
}
最丧也最甜 2024-08-13 11:06:20

我喜欢 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/ const_iterator 即使延迟返回类型为 C++0x)。

I liked KeithB's solution with free functions. However, a more reusable solution might be nice.

What about function objects that access first or second, as you can name the instances anything you like:

#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';
    }
}

This is the best I could do. I also tried to make those functors accept the iterator directly, but one way or another this means that the signature will contain dependent names which apparently makes template type deduction impossible (I couldn't find a way to overload GetSecond for iterator/const_iterator even with deferred return type of C++0x).

情感失落者 2024-08-13 11:06:20

我有一个邪恶的解决办法!

#define vertex first
#define edge second

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

添加是为了完整性。

不敢相信没有其他人提出这个建议。

I've got an evil solution!

#define vertex first
#define edge second

Although as an evil solution it will doubtless cause great trauma and difficult to diagnose compilation problems when you accidentally use those words elsewhere.

Added for completeness.

Can't believe nobody else has suggested this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文