ventajas sirve recorrer que patron para objeto iterador implementar hasnext ejemplo desventajas crear con como collection c++ stl map iterator

c++ - sirve - patron iterator ventajas y desventajas



Renombrando primero y segundo de un iterador de mapas (8)

¿Hay alguna forma de cambiar el nombre de la primera y la segunda función de acceso de un iterador de mapas? Entiendo que tienen estos nombres debido al par subyacente que representa la clave y el valor, pero me gustaría que los iteradores sean un poco más legibles. Creo que esto podría ser posible utilizando un adaptador de iterador, pero no estoy seguro de cómo implementarlo.

Tenga en cuenta que no puedo usar impulso.

Ejemplo de lo que quiero decir:

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 }


¡Tengo una mala solución!

#define vertex first #define edge second

Aunque como solución malvada, sin duda causará un gran trauma y será difícil diagnosticar problemas de compilación cuando accidentalmente use esas palabras en otros lugares.

Añadido para la integridad.

No puedo creer que nadie más haya sugerido esto.


Claro, reimplementar o envolver iterador, pero ¿vale la pena el esfuerzo? No podria

Vertex& v = it->first;

¿ser más fácil?


Lamentablemente no. Lo que suelo hacer es esto:

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

Para la legibilidad. Dentro de tu bucle también puedes decir

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


Me gustó la solución de KeithB con funciones gratuitas. Sin embargo, una solución más reutilizable podría ser agradable.

¿Qué pasa con los objetos de función que acceden primero o segundo, ya que puede nombrar a las instancias como desee?

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

Esto es lo mejor que pude hacer. También intenté hacer que esos funtores aceptaran el iterador directamente, pero de una manera u otra esto significa que la firma contendrá nombres dependientes que aparentemente hacen que la deducción del tipo de plantilla sea imposible (no pude encontrar una manera de sobrecargar GetSecond para iterator/const_iterator incluso con tipo de retorno diferido de C ++ 0x).


No puede cambiar el nombre de los miembros, pero puede tener algunas funciones para ayudar.

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

Entonces, en lugar de él it->vertex como quieras, puedes hacer vertex(it)


No recomendaría realmente usar esto, pero parece funcionar, al menos en el grado mínimo del programa de prueba haciendo lo que quería / esperaba:

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


Si no necesita el iterador (por ejemplo, un rango basado en el bucle se adapta a su propósito), a partir de c ++ 17 puede usar enlaces estructurados :

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


Si solo te preocupa la legibilidad, puedes hacer algo como esto:

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

Y entonces:

Vertex v = adjacency(it).vertex;