Para cualquiera a quien le guste la std::views::iota
respuesta de Cigien pero no esté trabajando en C ++ 20 o superior, es bastante sencillo implementar una versión simplificada y liviana de std::views::iota
compatiblec ++ 11 o superior.
Todo lo que requiere es:
- Un tipo básico " LegacyInputIterator " (algo que define
operator++
y operator*
) que envuelve un valor integral (por ejemplo, un int
)
- Alguna clase similar a "rango" que tiene
begin()
y end()
que devuelve los iteradores anteriores. Esto le permitirá trabajar en for
bucles basados en rangos.
Una versión simplificada de esto podría ser:
#include <iterator>
class counting_iterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = int;
using reference = int;
using pointer = int*;
using difference_type = std::ptrdiff_t;
constexpr explicit counting_iterator(int x) : m_value{x}{}
constexpr counting_iterator(const counting_iterator&) = default;
constexpr counting_iterator& operator=(const counting_iterator&) = default;
constexpr reference operator*() const { return m_value; }
constexpr pointer operator->() const { return &m_value; }
constexpr counting_iterator& operator++() {
m_value++;
return (*this);
}
constexpr counting_iterator operator++(int) {
const auto copy = (*this);
++(*this);
return copy;
}
constexpr bool operator==(const counting_iterator& other) const noexcept {
return m_value == other.m_value;
}
constexpr bool operator!=(const counting_iterator& other) const noexcept {
return m_value != other.m_value;
}
private:
int m_value;
};
struct iota_range
{
int first;
int last;
constexpr counting_iterator begin() const { return counting_iterator{first}; }
constexpr counting_iterator end() const { return counting_iterator{last}; }
};
constexpr iota_range iota(int first, int last)
{
return iota_range{first, last};
}
He definido lo anterior con constexpr
dónde es compatible, pero para versiones anteriores de C ++ como C ++ 11/14, es posible que deba eliminarlo constexpr
donde no es legal en esas versiones para hacerlo.
La plantilla anterior permite que el siguiente código funcione en versiones anteriores a C ++ 20:
for (int const i : iota(0, 10))
{
std::cout << i << " ";
i = 42;
}
Que generará el mismo ensamblado que la std::views::iota
solución C ++ 20 y la for
solución clásica -loop cuando se optimice.
Esto funciona con cualquier compilador compatible con C ++ 11 (por ejemplo, compiladores como gcc-4.9.4
) y aún produce un ensamblaje casi idéntico a un for
equivalente básico de bucle.
Nota: La iota
función auxiliar es solo para la paridad de características con la std::views::iota
solución C ++ 20 ; pero de manera realista, también podría construir directamente un en iota_range{...}
lugar de llamar iota(...)
. El primero solo presenta una ruta de actualización fácil si un usuario desea cambiar a C ++ 20 en el futuro.