Implementei um exemplo de iterador que conta cada incremento:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
template <class IteratorCategory = std::vector<int>::iterator::iterator_category>
class DereferenceCountingIterator : public std::vector<int>::iterator {
public:
using iterator_category = IteratorCategory;
public:
static std::size_t increaseCnt;
DereferenceCountingIterator(
typename std::vector<int>::iterator iter)
: std::vector<int>::iterator(iter) {}
auto& operator++() {
++increaseCnt;
return std::vector<int>::iterator::operator++();
}
DereferenceCountingIterator<IteratorCategory> operator+(difference_type diff) {
return static_cast<std::vector<int>::iterator&>(*this).operator+(diff);
}
};
Esta classe de modelo pode funcionar tanto como RandomAccess quanto como iterador de entrada:
template<class IteratorCategory>
std::size_t DereferenceCountingIterator<IteratorCategory>::increaseCnt = 0;
using RandomAccessDereferenceContingIterator = DereferenceCountingIterator<>;
using NonRandomAccessDereferenceContingIterator
= DereferenceCountingIterator<std::input_iterator_tag>;
O aplicativo com um exemplo:
int main() {
auto vec = std::vector<int>{3, 4, 5};
auto rAVecBegin = RandomAccessDereferenceContingIterator(vec.begin());
auto nonRAVecBegin = NonRandomAccessDereferenceContingIterator(vec.begin());
{
const auto incBefore = RandomAccessDereferenceContingIterator::increaseCnt;
auto out = std::vector<int>{};
std::copy_n(rAVecBegin, 3, std::back_inserter(out));
const auto incAfter = RandomAccessDereferenceContingIterator::increaseCnt;
std::cout << incAfter - incBefore << std::endl;
}
{
const auto incBefore = NonRandomAccessDereferenceContingIterator::increaseCnt;
auto out = std::vector<int>{};
std::copy_n(nonRAVecBegin, 3, std::back_inserter(out));
const auto incAfter = NonRandomAccessDereferenceContingIterator::increaseCnt;
std::cout << incAfter - incBefore << std::endl;
}
return 0;
}
A saída deste programa é a seguinte (in libstdc++
e libc++
):
3
2
Posso ter certeza de que isso aumenta copy_n
exatamente n-1
o iterador de origem se não for RandomAccessIterator e n
aumenta se for?
Não, não há exigência quanto ao número de incrementos.
Se o iterador for apenas um iterador de entrada, não um iterador de encaminhamento, então a implementação é forçada a fazer exatamente
n
oun-1
incrementar até o último iterador desreferenciado ou aquele após aquele que não foi desreferenciado, mas deve ser válido. Um iterador de entrada não pode ser iterado pela sequência de origem de nenhuma outra maneira.Se o iterador for um iterador direto ou mesmo um iterador de acesso aleatório, não há exigência quanto ao número de incrementos e a implementação também pode diminuir ou realizar etapas maiores do que incrementos/decrementos. Se o iterador for contíguo, ele poderá usar ponteiros em vez de iteradores para acessar elementos da sequência.
Também não há exigência de que a sequência seja copiada em ordem.
O único requisito de complexidade é que
n
as atribuições sejam feitas com exatidão.