Подтвердить что ты не робот

Переименование первого и второго итератора карты

Можно ли переименовать первую и вторую функции доступа к итератору карты. Я понимаю, что у них есть эти имена из-за базовой пары, которая представляет ключ и ценность, но я бы хотел, чтобы итераторы были немного более читабельными. Я думаю, что это возможно с помощью адаптера итератора, но я не уверен, как его реализовать.

Обратите внимание, что я не могу использовать 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
}
4b9b3361

Ответ 1

Если вас просто беспокоит читаемость, вы можете сделать что-то вроде этого:

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;

Ответ 2

Вы не можете переименовать элементы, но у вас могут быть некоторые функции.

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)

Ответ 3

К сожалению, нет. Обычно я делаю следующее:

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

Для удобства чтения. Внутри цикла вы также можете сказать

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

Ответ 4

Конечно, переопределить или обернуть итератор, но стоит ли это усилий? Не было бы

Vertex& v = it->first;

проще?

Ответ 5

Я бы не рекомендовал действительно использовать это, но, похоже, он работает, по крайней мере, до минимальной степени, чтобы тестовая программа выполняла то, что я хотел/ожидал:

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

Ответ 6

Мне понравилось решение 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 даже с отложенный тип возврата С++ 0x).

Ответ 7

У меня есть злые решения!

#define vertex first
#define edge second

Несмотря на то, что это злое решение, оно, несомненно, вызовет серьезные травмы и затруднит диагностику проблем с компиляцией, когда вы случайно используете эти слова в другом месте.

Добавлен для полноты.

Не могу поверить, что никто этого не предложил.