que - ¿Existe una clase de rango en C++ 11 para usar con rangos basados en rangos?
programa que imprima los numeros pares en c++ (8)
Aquí hay una forma más simple que funciona bien para mí. ¿Hay algún riesgo en mi enfoque?
r_iterator
es un tipo que se comporta, en la medida de lo posible, como un long int
. Por lo tanto, muchos operadores, como ==
y ++
, simplemente pasan a la long int
. ''Expongo'' el int largo subyacente a través del operator long int
y operator long int &
conversiones.
#include <iostream>
using namespace std;
struct r_iterator {
long int value;
r_iterator(long int _v) : value(_v) {}
operator long int () const { return value; }
operator long int& () { return value; }
long int operator* () const { return value; }
};
template <long int _begin, long int _end>
struct range {
static r_iterator begin() {return _begin;}
static r_iterator end () {return _end;}
};
int main() {
for(auto i: range<0,10>()) { cout << i << endl; }
return 0;
}
( Editar: - podemos hacer que los métodos de range
estáticos en lugar de const)
Me encontré escribiendo esto hace un momento:
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 convertido en parte del estándar.
¿Por lo que es? ¿Se ha agregado algún tipo de biblioteca nueva para iteradores en un rango de enteros, o tal vez un rango genérico de valores escalares computados?
Descubrí que boost::irange
era mucho más lento que el bucle entero canónico. Así que me decidí por la siguiente solución mucho más simple usando una macro de preprocesador:
#define RANGE(a, b) unsigned a=0; a<b; a++
Entonces puedes hacer un loop así:
for(RANGE(i, n)) {
// code here
}
Este rango comienza automáticamente desde cero. Podría extenderse fácilmente para comenzar desde un número determinado.
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 una 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 como encanto con bucles de rango basado en C ++ 11 :)
Caracteristicas :
Un verdadero contenedor de acceso aleatorio con todas las campanas y silbatos!
Los rangos se pueden comparar lexicográficamente.
Existen dos funciones (devuelve bool) y
find
(devuelve iterador) para verificar la existencia de un número.La biblioteca se prueba en unidades usando CATCH .
Ejemplos de uso básico, trabajar con contenedores estándar, trabajar con algoritmos estándar y trabajar con bucles basados en rangos.
Aquí hay una introducción de un minuto . Finalmente, doy la bienvenida a cualquier sugerencia sobre esta pequeña biblioteca.
Esto podría ser un poco tarde, pero acabo de ver esta pregunta y he estado usando esta clase por un tiempo:
#include <iostream>
#include <utility>
#include <stdexcept>
template<typename T, bool reverse = false> struct Range final {
struct Iterator final{
T value;
Iterator(const T & v) : value(v) {}
const Iterator & operator++() { reverse ? --value : ++value; return *this; }
bool operator!=(const Iterator & o) { return o.value != value; }
T operator*() const { return value; }
};
T begin_, end_;
Range(const T & b, const T & e) : begin_(b), end_(e) {
if(b > e) throw std::out_of_range("begin > end");
}
Iterator begin() const { return reverse ? end_ -1 : begin_; }
Iterator end() const { return reverse ? begin_ - 1: end_; }
Range() = delete;
Range(const Range &) = delete;
};
using UIntRange = Range<unsigned, false>;
using RUIntRange = Range<unsigned, true>;
Uso:
int main() {
std::cout << "Reverse : ";
for(auto i : RUIntRange(0, 10)) std::cout << i << '' '';
std::cout << std::endl << "Normal : ";
for(auto i : UIntRange(0u, 10u)) std::cout << i << '' '';
std::cout << std::endl;
}
Hasta donde yo sé, no existe tal clase en C ++ 11.
De todos modos, traté de mejorar tu implementación. Lo hice sin plantilla , ya que no veo ninguna ventaja en convertirlo en plantilla . Por el contrario, tiene una gran desventaja: que no puede crear el rango en tiempo de ejecución, ya que necesita conocer los argumentos de la plantilla en el momento de la compilación.
//your version
auto x = range<m,n>(); //m and n must be known at compile time
//my version
auto x = range(m,n); //m and n may be known at runtime as well!
Aquí está el código:
class range {
public:
class iterator {
friend class range;
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 begin_; }
iterator end() const { return end_; }
range(long int begin, long int end) : begin_(begin), end_(end) {}
private:
iterator begin_;
iterator end_;
};
Código de prueba:
int main() {
int m, n;
std::istringstream in("10 20");
if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru.
{
if ( m > n ) std::swap(m,n);
for (auto i : range(m,n))
{
std::cout << i << " ";
}
}
else
std::cout <<"invalid input";
}
Salida:
10 11 12 13 14 15 16 17 18 19
La biblioteca estándar de C ++ no tiene una, pero Boost.Range tiene boost :: counting_range , que ciertamente califica. También podría usar boost::irange , que está un poco más enfocado en el alcance.
Puede generar fácilmente una secuencia creciente en C ++ 11 usando std :: iota ():
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template<typename T>
std::vector<T> range(T start, T end)
{
std::vector<T> r(end+1-start, T(0));
std::iota(r.begin(), r.end(), T(start));//increasing sequence
return r;
}
int main(int argc, const char * argv[])
{
for(auto i:range<int>(-3,5))
std::cout<<i<<std::endl;
return 0;
}
has intentado usar
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function f);
La mayoría de las veces se ajusta a la ley.
P.ej
template<class T> void printInt(T i) {cout<<i<<endl;}
void test()
{
int arr[] = {1,5,7};
vector v(arr,arr+3);
for_each(v.begin(),v.end(),printInt);
}
Tenga en cuenta que printInt puede reemplazarse por OFC con una lambda en C ++ 0x. También una pequeña variación más de este uso podría ser (estrictamente para random_iterator)
for_each(v.begin()+5,v.begin()+10,printInt);
Para Fwd solo iterador
for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);