¿Las categorías de iteradores de C ++ no permiten escribir un adaptador de iterador UTF-8?

8

He estado trabajando en un adaptador iterador UTF-8. Por lo cual, me refiero a un adaptador que convierte un iterador en una secuencia char o unsigned char en un iterador en una secuencia char32_t . Mi trabajo aquí se inspiró en este iterador que encontré en línea .

Sin embargo, cuando revisé el estándar cuando estaba iniciando mi propia implementación, llegué a la conclusión: no parece ser posible implementar un adaptador de este tipo al mismo tiempo que cumple con los requisitos que C ++ impone a los iteradores.

Por ejemplo, ¿podría crear un iterador UTF-8 que satisfaga los requisitos de InputIterator? Sí, pero solo en la medida en que el iterador que se le proporcione no sea no en sí mismo un InputIterator. ¿Por qué?

Porque InputIterator requiere la capacidad de eliminar la referencia al mismo iterador más de una vez. También puede eliminar referencias de varias copias de ese iterador, siempre que todas se comparen de la misma manera.

Por supuesto, la anulación de la referencia de un adaptador iterador UTF-8 requiere tanto la anulación de la referencia como la posibilidad de incrementar el iterador base. Y si ese iterador es un InputIterator, entonces no puede recuperar el valor original después de incrementarlo. Y el hecho de que las copias tengan que funcionar significa que no puede almacenar localmente un char32_t que represente el valor descodificado previamente. Podrías haber hecho esto:

auto it = ...
auto it2 = it; //Copies an empty 'char32_t'.
*it;           //Accesses base iterator, storing 'it.ch'.
*it;           //Doesn't access the base iterator; simply returns 'it.ch'.
*it2;          //Cannot access 'it.ch', so must access base iterator.

Bien, bien, así que no puedes usar InputIterators. Pero ¿qué pasa con ForwardIterator? ¿Es posible crear un adaptador ForwardIterator que pueda adaptar ForwardIterators a través de secuencias de caracteres UTF-8?

Eso también es problemático, porque la operación *it es requerida para producir value_type& o const value_type& . Los InputIterators pueden escupir cualquier cosa que sea convertible a value_type , pero se requiere un ForwardIterator para proporcionar una referencia real [forward.iterators] /1.3:

  

si X es un iterador mutable, reference es una referencia a T ; Si X es un iterador constante, reference es una referencia a const T

El único recurso aquí es que cada iterador tenga un char32_t , que existe únicamente para proporcionar el almacenamiento para esa referencia. E incluso entonces, ese valor tendrá que actualizarse cada vez que la instancia del iterador se incremente y se elimine la referencia. Esto invalida efectivamente la referencia anterior, y el estándar no lo permite explícitamente (la invalidación solo puede ocurrir cuando se destruye un iterador, o si el contenedor lo dice).

El código mencionado anteriormente que encontré en línea no es válido debido a esto, ya que devuelve un uint32_t (escrito antes de C ++ 11) por valor en lugar de una referencia adecuada.

¿Hay algún recurso aquí? ¿He pasado por alto algo en el estándar o alguna técnica de implementación que podría usar para evitar estos problemas? ¿O simplemente no es posible con la redacción actual de la norma?

Nota: lo extraño es que parece que es posible escribir un OutputIterator conforme para la conversión de UTF-8. Es decir, un tipo que toma char32_t y escribe UTF-8 en un char o unsigned char OutputIterator.

    
pregunta Nicol Bolas 01.04.2017 - 20:43

1 respuesta

3

Creo que la respuesta corta es sí. Un adaptador de iterador que decodifica UTF-8 (y más generalmente, que potencialmente requiere que múltiples elementos de entrada produzcan un solo elemento de salida) debe colocarse sobre un iterador que modela (al menos) el BidirectionalIterator.

Tenga en cuenta que esto supone que solo desea un iterador constante (es decir, que solo lee UTF-8 desde la entrada, no escribe UTF-8 en la colección subyacente). Si desea admitir la escritura, las cosas se ponen más feas en un apuro: el cambio de un valor a otro en el nivel UTF-32 podría producir fácilmente una codificación UTF-8 que tiene un tamaño diferente, por lo que debe estar preparado para insertar / eliminar elementos en medio de la colección subyacente si iba a admitir la escritura.

    
respondido por el Jerry Coffin 04.04.2017 - 17:10

Lea otras preguntas en las etiquetas