Estou trabalhando em um adaptador iterador UTF-8. Com isso, quero dizer um adaptador que transforma um iterador em uma sequência char
ou unsigned char
em um iterador em uma char32_t
sequência. Meu trabalho aqui foi inspirado neste iterador que encontrei online .
No entanto, ao examinar o padrão quando estava iniciando minha própria implementação, cheguei a uma conclusão: não parece possível implementar esse adaptador enquanto ainda está em conformidade com os requisitos que o C ++ impõe aos iteradores.
Por exemplo, você poderia criar um iterador UTF-8 que atenda aos requisitos do InputIterator? Sim, mas apenas enquanto o iterador fornecido não for um InputIterator. Por quê?
Como o InputIterator requer a capacidade de desreferenciar o mesmo iterador mais de uma vez. Você também pode desreferenciar várias cópias desse iterador, desde que todas sejam iguais.
Obviamente, desreferenciar um adaptador iterador UTF-8 requer desreferenciar e potencialmente incrementar o iterador base. E se esse iterador for um InputIterator, não será possível recuperar o valor original depois de incrementá-lo. E o fato de as cópias terem que funcionar significa que você não pode armazenar localmente um char32_t
que represente o valor decodificado anteriormente. Você poderia ter feito isso:
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.
OK, tudo bem, então você não pode usar InputIterators. Mas e o ForwardIterator? É possível criar um adaptador ForwardIterator que possa adaptar o ForwardIterators sobre seqüências de caracteres UTF-8?
Isso também é problemático, porque a operação *it
é necessária para produzir value_type&
ou const value_type&
. InputIterators pode cuspir qualquer coisa que seja conversível value_type
, mas ForwardIterator
é necessário fornecer uma referência real [forward.iterators] /1.3:
if
X
é um iterador mutável,reference
é uma referência aT
; ifX
é um iterador constante,reference
é uma referência aconst T
O único recurso aqui é que todo iterador carregue um a char32_t
, que existe apenas para fornecer o armazenamento para essa referência. E mesmo assim, esse valor precisará ser atualizado sempre que a instância do iterador for incrementada e desreferenciada. Isso efetivamente invalida a referência antiga, e o padrão não permite explicitamente isso (a invalidação só pode acontecer quando um iterador é destruído ou se o contêiner diz isso).
O código mencionado acima, encontrado on-line, não é válido devido a isso, pois retorna a uint32_t
(pré-C ++ 11 escrito) por valor, em vez de uma referência adequada.
Existe algum recurso aqui? Eu negligenciei algo no padrão ou alguma técnica de implementação que eu poderia usar para contornar esses problemas? Ou isso simplesmente não é possível com a redação atual do padrão?
Nota: o estranho é que parece possível escrever um OutputIterator em conformidade para a conversão UTF-8. Ou seja, um tipo que pega char32_t
e grava UTF-8 em um char
ou unsigned char
OutputIterator.
ForwardIterator
não se encaixava bem com nenhum tipo de iterador de proxy , como aqueles que tornaramvector<bool>
possível. Havia um artigo bem conhecido, escrito em 1999 por Herb Sutter, que explicava por que essa determinação foi feita. Nos tempos modernos, havia uma tendência de repensar essa questão. Acho um escrito por Eric Niebler . Pode haver mais; pode até haver alguns escritos pelo próprio Herb Sutter, em algumas propostas de C ++.