Bienvenidos sean a este post, hoy analizaremos como trabajan los iteradores nuevos.
Si vienen de posts anteriores, ya hemos estado usando distintos tipos de iteradores. Desde colecciones simples como un array hasta los contenedores de los ultimos posts. Pero en el post anterior mencionamos que a partir de C++ 20 se agrego a los conceptos para usar con los iteradores. En ese post mostramos un ejemplo simple de como se aplica, como funciona y como crearlo. Tambien mencionamos que existen unos conceptos estandar definidos en la libreria concepts. Algunos conceptos que disponemos son:
- readable, especificas que el tipo es leible aplicando al operador de puntero
- writable, especifica que un valor puede ser escrito al objeto referenciado por el iterador
Tambien disponemos de otro llamado incrementable pero este se encuentra definido en la libreria iterator. Veamos como esta deffinida:
template <typename T>
concept incrementable = std::regular<T> && std::weakly_incrementable<T>
&& requires (T t) { {t++} -> std::same_as<T>; };
La primera particularidad de este concepto es que necesita del tipo regular. Esto implica que debe ser constructible de manera predeterminada, tener un constructor de copia y operator==(). Ademas de lo anterior, este necesita del tipo weakly_incrementable. Esto hace que el tipo soporte operadores de pre y pos incremento, excepto si no se requiere que el tipo sea comparable en igualdad. Es por eso que las uniones incrementales std::regular requieren que el tipo sea comparable en igualdad. Por ultimo, la adicion requiere una restriccion, pensado principalmente por el hecho de que el tipo no debe cambiar luego del incremento, siendo siempre el mismo despues de la accion. A pesar de que std::same_as es representado como un concepto, definido en la libreria concepts, y si bien se puede usar a std::is_same definido en la libreria type_traits, estos hacen basicamente lo mismo.
Con esto comentado, podemos reemplazar las categorias de iteracion que hablamos en este post por los conceptos de iteracion. Ademas de los mencionados anteriormente deberiamos agregar los siguientes:
- input_iterator, especifica que puede ser leido y soporta la pre y pos incrementacion
- output_iterator, especifica que puede ser escrito y tambien soporta pre y pos incrementacion
- input_or_output_iterator, especifica que puede ser incrementable y desreferenciado
- forward_iterator, especifica que es un input_iterator que tambien soporta comparacion de igualdad y multi-pase
- bidirectional_iterator, especifica que soporta a forward_iterator y tambien soporta retroceso en el movimiento
- random_access_iterator, especifica que el tipo es un bidirectional_iterator y soporta libre movimiento en el mismo
- contiguous_iterator, especifica que el tipo es un random_access_iterator, referenciando que los elementos son continuos en memoria
Si los comparamos no solo son similares en nombre a los iteradores heredados sino que tambien lo son en sus acciones. Pero ahora tenemos la ventaja de poder usarlo en los parametros de template para que el compilador se haga cargo de todo.
En resumen, hoy hemos visto a los nuevos iteradores, como son, como se comportan, sus similitudes y diferencias con los heredados. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donatión
It’s for site maintenance, thanks!
$1.50
