2008-11-23 9 views
9

Tengo un contenedor lleno de pares. Quiero iterar en él usando los algoritmos genéricos de STL (en mi caso sería inner_product, pero considérelo como un problema genérico). El algoritmo que estoy usando espera iteradores primero y último. ¿Puedo proporcionar iteradores especiales primero y último que iterarán no en los pares sino en el primer elemento de cada par?Proporcionando un iterador para el primer elemento de un contenedor de pares

Sé que puedo hacerlo de forma manual, proporcionando un objeto de función hecho a mano que será un envoltorio alrededor del iterador de contenedor estándar, haciendo referencia al primer miembro del par de la intención del par en sí, pero creo que hay también un ingenioso trazador de líneas para hacerlo por mí. ¿Qué podría ser?

+0

Quiere decir, por ejemplo, que tiene un map.begin(), y desea iterar sobre sus valores (.second)? –

+0

Sí, esa es otra instancia del mismo problema básico. –

+0

¿Está permitido aumentar? :) –

Respuesta

11

Miré alrededor y encontré boost::transform_iterator. He creado este código. Sorprendente lo bien que funciona:

#include <map> 
#include <algorithm> 
#include <iostream> 
#include <string> 
#include <iterator> 
#include <boost/iterator/transform_iterator.hpp> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 

int main() { 
    typedef std::map<std::string, int>::value_type value_type; 
    std::map<std::string, int> a; 
    a["one"] = 1; 
    a["two"] = 2; 

    // returns the second element 
    boost::function<int(value_type&)> f = boost::bind(&value_type::second, _1); 
    std::copy(boost::make_transform_iterator(a.begin(), f), 
       boost::make_transform_iterator(a.end(), f), 
       std::ostream_iterator<int>(std::cout, " ")); 

} 

Es la impresión "1 2 " a la salida estándar.

+0

Es lo más parecido a una "solución inteligente de un trazador de líneas" como creo que obtendremos ... :-) –

+0

+1: es demasiado tarde para responder .... –

+0

usted * podría * poner todo en una línea. pero tendrías que repetir la llamada de enlace. feo código copy'n'paste luego :) –

1

Puede crear la subclase, p. std :: vector :: const_iterator usted mismo, reimplementando el operador * y el operador-> para devolver el primero del par. También necesitaría crear sus propias funciones de inicio() y final() para devolver su iterador personalizado.

También puede crear clases de funciones binarias y pasarlas a inner_product.

+0

¿Estás seguro de que puedo subclase stl iterators? Siempre pensé que no proporcionaban destructores virtuales ni habilitaban la creación de subclases. –

+0

No dije subclass std :: iterator. Dije la subclase std :: vector :: const_iterator. Lo intenté hace un momento, y funciona. – strager

+0

usted * puede * (lo siento, mi comentario dice "no puedo", de hecho quise decir "puede") subclase de std :: iterator de hecho. proporciona los tipos de archivos comunes necesarios. su propósito no es proporcionar una interfaz polimórfica –

1

No existe una solución inteligente de una sola línea. Su mejor esperanza es escribir un iterador de envoltura. Esta es en realidad una solución bastante canónica. Puede verificar si Boost ya tiene lo que necesita. Si no, intente escribir un contenedor genérico que pueda reutilizarse para otros problemas.

El STL contiene un envoltorio de iterador de este tipo llamado reverse_iterator. El nombre implica su uso.

1

En última instancia, creo que su idea es el camino a seguir. Puedes usar Boost para ayudarte a hacerlo. Para empezar, necesitaría una función que tome su par y devuelva el primer elemento. Creo que podría escribir esa función en línea usando el Lambda library, pero, para mayor legibilidad, creo que simplemente escribiría una función simple que lo haga en su lugar. Luego pase esa función con sus iteradores originales para construir un transform_iterator para el inicio y el fin de su secuencia.

Cuestiones relacionadas