Ok, así que esta no es una solución completa, pero me quedé sin tiempo. Por lo tanto, actualmente no se implementa un iterador completo, sino una clase reducida de tipo iterador que define algo así como esta interfaz y requiere C++ 11. Lo he probado en g ++ 4.7:
template<typename NestedContainerType, typename Terminator>
class flatten_iterator
{
bool complete();
void advance();
Terminator& current();
};
Dónde NestedContainerType
es el tipo de contenedor anidado (sorprendentemente), y Terminator es el tipo de lo más interno que está queriendo salir de la aplanar.
El siguiente código funciona, pero ciertamente no se ha probado exhaustivamente. Envolverlo por completo (suponiendo que esté satisfecho con el avance adelantado solamente) no debería ser demasiado trabajo, en particular si usa boost::iterator_facade
.
#include <list>
#include <deque>
#include <vector>
#include <iostream>
template<typename ContainerType, typename Terminator>
class flatten_iterator
{
public:
typedef flatten_iterator<typename ContainerType::value_type, Terminator> inner_it_type;
typedef typename inner_it_type::value_type value_type;
public:
flatten_iterator() {}
flatten_iterator(ContainerType& container) : m_it(container.begin()), m_end(container.end())
{
skipEmpties();
}
bool complete()
{
return m_it == m_end;
}
value_type& current()
{
return m_inner_it.current();
}
void advance()
{
if (!m_inner_it.complete())
{
m_inner_it.advance();
}
if (m_inner_it.complete())
{
++m_it;
skipEmpties();
}
}
private:
void skipEmpties()
{
while (!complete())
{
m_inner_it = inner_it_type(*m_it);
if (!m_inner_it.complete()) break;
++m_it;
}
}
private:
inner_it_type m_inner_it;
typename ContainerType::iterator m_it, m_end;
};
template<template<typename, typename ...> class ContainerType, typename Terminator, typename ... Args>
class flatten_iterator<ContainerType<Terminator, Args...>, Terminator>
{
public:
typedef typename ContainerType<Terminator, Args...>::value_type value_type;
public:
flatten_iterator() {}
flatten_iterator(ContainerType<Terminator, Args...>& container) :
m_it(container.begin()), m_end(container.end())
{
}
bool complete()
{
return m_it == m_end;
}
value_type& current() { return *m_it; }
void advance() { ++m_it; }
private:
typename ContainerType<Terminator, Args...>::iterator m_it, m_end;
};
Y con los siguientes casos de prueba, se hace lo que se puede esperar:
int main(int argc, char* argv[])
{
typedef std::vector<int> n1_t;
typedef std::vector<std::deque<short> > n2_t;
typedef std::list<std::vector<std::vector<std::vector<double> > > > n4_t;
typedef std::vector<std::deque<std::vector<std::deque<std::vector<std::list<float> > > > > > n6_t;
n1_t n1 = { 1, 2, 3, 4 };
n2_t n2 = { {}, { 1, 2 }, {3}, {}, {4}, {}, {} };
n4_t n4 = { { { {1.0}, {}, {}, {2.0}, {} }, { {}, {} }, { {3.0} } }, { { { 4.0 } } } };
n6_t n6 = { { { { { {1.0f}, {}, {}, {2.0f}, {} }, { {}, {} }, { {3.0f} } }, { { { 4.0f } } } } } };
flatten_iterator<n1_t, int> i1(n1);
while (!i1.complete())
{
std::cout << i1.current() << std::endl;
i1.advance();
}
flatten_iterator<n2_t, short> i2(n2);
while (!i2.complete())
{
std::cout << i2.current() << std::endl;
i2.advance();
}
flatten_iterator<n4_t, double> i4(n4);
while (!i4.complete())
{
std::cout << i4.current() << std::endl;
i4.advance();
}
flatten_iterator<n6_t, float> i6(n6);
while (!i6.complete())
{
std::cout << i6.current() << std::endl;
i6.advance();
}
}
Así que imprime la siguiente para cada uno de los tipos de contenedores:
1
2
3
4
Tenga en cuenta que doesn Todavía no funciona con set
s porque se necesita algo de tiempo para lidiar con el hecho de que los iteradores set
devuelven las referencias const. Ejercicio para el lector ... :-)
wow. se ve bien, funciona, muy cerca de lo que necesito. Un comentario: trato de usar las bibliotecas más pequeñas que sea necesario. Entonces, ¿el 'boost :: scoped_ptr' es realmente necesario? – steffen
El 'scoped_ptr' no es totalmente necesario. Simplemente almacene el iterador por valor. –
??? Supongo que estoy cometiendo un error estúpido, pero la línea 'typename inner_it_type m_inner_it;' da el error del compilador 'expected nest-name-specifier before 'inner_it_type'' – steffen