Me encontré escribiendo esto hace un poco:
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>();
}
Y esto me permite escribir cosas como esta:
for (auto i: range<0, 10>()) {
// stuff with i
}
Ahora, sé que lo que escribí quizás no sea el mejor código. Y tal vez haya una forma de hacerlo más flexible y útil. Pero me parece que algo como esto debería haberse incluido en el estándar.
¿Por lo que es? ¿Se agregó algún tipo de biblioteca nueva para iteradores en un rango de enteros, o tal vez un rango genérico de valores escalares calculados?
range
la función de plantilla? No agrega nada al uso en el querange_class
se usa. Quiero decir, ¡range<0,10>()
yrange_class<0,10>()
lucir exactamente igual!Respuestas:
La biblioteca estándar de C ++ no tiene uno, pero Boost.Range tiene boost :: counting_range , que ciertamente califica. También puede usar boost :: irange , que tiene un alcance un poco más centrado.
La biblioteca de rango de C ++ 20 le permitirá hacer esto a través de
view::iota(start, end)
.fuente
std::experimental::ranges
espacio de nombres.range-v3
Siempre fue una especie de implementación de referencia, diría yo. Pero ahora creo que las cosas del rango básico también se votaron recientemente en C ++ 20, ¡así que de hecho lo tendremosstd::
pronto! :-)Hasta donde yo sé, no existe tal clase en C ++ 11.
De todos modos, intenté mejorar su implementación. Lo hice sin plantilla , ya que no veo ninguna ventaja en lo que es template . Por el contrario, tiene una desventaja importante: que no puede crear el rango en tiempo de ejecución, ya que necesita conocer los argumentos de la plantilla en el tiempo de compilación.
Aquí está el código:
Código de prueba:
Salida:
10 11 12 13 14 15 16 17 18 19
Demostración en línea .
fuente
iterator
paraconst_iterator
, teneriterator
derivadostd::iterator
y tenerrange
implementadocbegin
ycend
. Ah, y ... ¿por quéiterator::operator++
devuelve una referencia constante ?[begin, end)
. @OP: +1 para el juego de palabras en bucles basados en rango que no es un juego de palabras :-)v++
que se supone que devuelve el valor antes de que tuviera lugar la operación de incremento. Te aconsejo que explores la diferencia entre++i
yi++
dóndei
se declara estarint
.Escribí una biblioteca llamada
range
para exactamente el mismo propósito, excepto que es un rango de tiempo de ejecución, y la idea en mi caso vino de Python. Consideré una versión en tiempo de compilación, pero en mi humilde opinión, no hay ninguna ventaja real para ganar la versión en tiempo de compilación. Puede encontrar la biblioteca en bitbucket, y está bajo Boost License: Range . Es una biblioteca de un encabezado, compatible con C ++ 03 y funciona a la perfección con bucles for basados en rangos en C ++ 11 :)Caracteristicas :
¡Un verdadero contenedor de acceso aleatorio con todas las campanas y silbidos!
Los rangos se pueden comparar lexicográficamente.
Dos funciones
exist
(devuelve bool) yfind
(devuelve iterador) para comprobar la existencia de un número.La biblioteca se prueba unitariamente mediante CATCH .
Ejemplos de uso básico, trabajar con contenedores estándar, trabajar con algoritmos estándar y trabajar con rangos basados en bucles for.
Aquí hay una introducción de un minuto . Finalmente, agradezco cualquier sugerencia sobre esta pequeña biblioteca.
fuente
Descubrí que
boost::irange
era mucho más lento que el ciclo de enteros canónicos. Así que me decidí por la siguiente solución mucho más simple usando una macro de preprocesador:Entonces puedes hacer un bucle como este:
Este rango comienza automáticamente desde cero. Se podría ampliar fácilmente para empezar desde un número determinado.
fuente
for (RANGE(i, flag? n1: n2))
producirá resultados sorprendentes, porque no siguió una de las Reglas básicas de las macros no malvadas, que es poner entre paréntesis todos sus parámetros (incluido, en este caso,b
). Su enfoque tampoco proporciona ningún beneficio de rendimiento sobre el enfoque no macro basado en "objeto de rango" (por ejemplo, la respuesta de Nawaz ).Aquí hay una forma más simple que me está funcionando muy bien. ¿Existe algún riesgo en mi enfoque?
r_iterator
es un tipo que se comporta, en la medida de lo posible, como unlong int
. Por lo tanto, muchos operadores, como==
y++
, simplemente pasan along int
. 'Expongo' el int largo subyacente a través de las conversionesoperator long int
yoperator long int &
.( Editar: podemos hacer que los métodos sean
range
estáticos en lugar de const.)fuente
Esto puede ser un poco tarde, pero acabo de ver esta pregunta y he estado usando esta clase por un tiempo:
Uso:
fuente
has intentado usar
La mayoría de las veces se ajusta a los requisitos.
P.ej
Tenga en cuenta que printInt puede reemplazarse OFC con una lambda en C ++ 0x. También podría ser una pequeña variación más de este uso (estrictamente para random_iterator)
Para iterador solo de Fwd
fuente
Puede generar fácilmente una secuencia creciente en C ++ 11 usando std :: iota ():
fuente
range
clase modelará el rango. Sin embargo, literalmente lo estás construyendo. Eso es una pérdida de memoria y accesos a la memoria. La solución es altamente redundante, porque el vector no contiene información real excepto por el número de elementos y el valor del primer elemento (si existe).