Eu me peguei escrevendo isso há pouco:
template <long int T_begin, long int T_end>
class range_class {
public:
class iterator {
friend class range_class;
public:
long int operator *() const { return i_; }
const iterator &operator ++() { ++i_; return *this; }
iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }
bool operator ==(const iterator &other) const { return i_ == other.i_; }
bool operator !=(const iterator &other) const { return i_ != other.i_; }
protected:
iterator(long int start) : i_ (start) { }
private:
unsigned long i_;
};
iterator begin() const { return iterator(T_begin); }
iterator end() const { return iterator(T_end); }
};
template <long int T_begin, long int T_end>
const range_class<T_begin, T_end>
range()
{
return range_class<T_begin, T_end>();
}
E isso me permite escrever coisas como:
for (auto i: range<0, 10>()) {
// stuff with i
}
Agora, eu sei que o que escrevi talvez não seja o melhor código. E talvez haja uma maneira de torná-lo mais flexível e útil. Mas me parece que algo assim deveria fazer parte do padrão.
Então é isso? Foi adicionado algum tipo de nova biblioteca para iteradores em um intervalo de inteiros ou talvez um intervalo genérico de valores escalares computados?
range
função de modelo? Não acrescenta nada ao uso em querange_class
é usado. Quero dizer,range<0,10>()
erange_class<0,10>()
parecem exatamente iguais!Respostas:
A biblioteca padrão C ++ não tem um, mas Boost.Range tem boost :: counter_range , que certamente se qualifica. Você também pode usar boost :: irange , que é um pouco mais focado no escopo.
A biblioteca range do C ++ 20 permitirá que você faça isso via
view::iota(start, end)
.fonte
std::experimental::ranges
namespace.range-v3
sempre foi uma espécie de implementação de referência, eu diria. Mas agora eu acredito que as coisas básicas da gama também foram recentemente votadas em C ++ 20, então nós iremos colocá-las emstd::
breve! :-)Pelo que eu sei, essa classe não existe em C ++ 11.
Enfim, tentei melhorar sua implementação. Eu o tornei não modelo , pois não vejo nenhuma vantagem em torná-lo modelo . Ao contrário, tem uma grande desvantagem: você não pode criar o intervalo em tempo de execução, pois você precisa saber os argumentos do modelo no próprio tempo de compilação.
Aqui está o código:
Código de teste:
Resultado:
10 11 12 13 14 15 16 17 18 19
Demonstração onine .
fonte
iterator
paraconst_iterator
,iterator
derivar destd::iterator
erange
implementarcbegin
ecend
. Ah e ... por queiterator::operator++
retorna uma referência const ?[begin, end)
. @OP: +1 para o trocadilho com loops baseados em alcance que não é um trocadilho :-)v++
que deve retornar o valor antes da operação de incremento ocorrer. Aconselho você a explorar a diferença entre++i
ei++
ondei
está declaradoint
.Eu escrevi uma biblioteca chamada
range
exatamente para o mesmo propósito, exceto que é um intervalo de tempo de execução, e a ideia no meu caso veio do Python. Eu considerei uma versão em tempo de compilação, mas na minha humilde opinião não há nenhuma vantagem real em obter a versão em tempo de compilação. Você pode encontrar a biblioteca no bitbucket, e está em Boost License: Range . É uma biblioteca de um cabeçalho, compatível com C ++ 03 e funciona perfeitamente com loops for baseados em intervalo em C ++ 11 :)Características :
Um verdadeiro contêiner de acesso aleatório com todos os sinos e assobios!
Os intervalos podem ser comparados lexicograficamente.
Duas funções
exist
(retorna bool) efind
(retorna iterador) para verificar a existência de um número.A biblioteca é testada por unidade usando CATCH .
Exemplos de uso básico, trabalhando com contêineres padrão, trabalhando com algoritmos padrão e trabalhando com loops for baseados em alcance.
Aqui está uma introdução de um minuto . Por fim, agradeço qualquer sugestão sobre esta pequena biblioteca.
fonte
Descobri que
boost::irange
era muito mais lento do que o loop inteiro canônico. Então, decidi pela seguinte solução muito mais simples usando uma macro de pré-processador:Então você pode fazer um loop assim:
Este intervalo começa automaticamente do zero. Ele poderia ser facilmente estendido para começar a partir de um determinado número.
fonte
for (RANGE(i, flag? n1: n2))
produzirá resultados surpreendentes, porque você falhou em seguir uma das Regras Básicas de Macros Não-Mal, que é colocar entre parênteses todos os seus parâmetros (incluindo, neste caso,b
). Sua abordagem também não fornece nenhum benefício de desempenho em relação à abordagem não macro, baseada em "objeto de alcance" (por exemplo, a resposta de Nawaz ).Aqui está um formulário mais simples que está funcionando bem para mim. Existe algum risco na minha abordagem?
r_iterator
é um tipo que se comporta, tanto quanto possível, como along int
. Portanto, muitos operadores como==
e++
simplesmente passam para olong int
. Eu "exponho" o int longo subjacente por meio das conversõesoperator long int
eoperator long int &
( Editar: - podemos fazer os métodos de
range
estático em vez de const.)fonte
Pode ser um pouco tarde, mas acabei de ver esta pergunta e estou usando esta classe há algum tempo:
Uso:
fonte
você já tentou usar
Na maioria das vezes se encaixa a conta.
Por exemplo
Observe que printInt pode ser substituído por um lambda em C ++ 0x. Além disso, mais uma pequena variação desse uso pode ser (estritamente para random_iterator)
Para iterador Fwd apenas
fonte
Você pode gerar facilmente uma sequência crescente em C ++ 11 usando std :: iota ():
fonte
range
classe deve modelar o intervalo. No entanto, você está literalmente construindo. Isso é um desperdício de memória e acessos à memória. A solução é altamente redundante, porque o vetor não contém nenhuma informação real, exceto para o número de elementos e o valor do primeiro elemento (se existir).