Dla każdego, kto lubi std::views::iota
odpowiedź Cigiena, ale nie działa w C ++ 20 lub nowszym, wdrożenie uproszczonej i lekkiej wersji std::views::iota
kompatybilnegoc ++ 11 lub wyższy.
Wystarczy:
- Podstawowy typ „ LegacyInputIterator ” (coś, co definiuje
operator++
i operator*
), który otacza wartość całkowitą (np. int
)
- Pewna klasa podobna do „zakresu”, która ma
begin()
i end()
zwraca powyższe iteratory. Umożliwi to pracę w for
pętlach opartych na zasięgu
Uproszczona wersja może wyglądać następująco:
#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};
}
Powyżej zdefiniowałem, constexpr
gdzie jest obsługiwane, ale w przypadku wcześniejszych wersji C ++, takich jak C ++ 11/14, może być konieczne usunięcie, constexpr
jeśli nie jest to legalne w tych wersjach, aby to zrobić.
Powyższy schemat umożliwia działanie następującego kodu w wersji przed C ++ 20:
for (int const i : iota(0, 10))
{
std::cout << i << " ";
i = 42;
}
Który wygeneruje ten sam zestaw co rozwiązanie C ++ 20 std::views::iota
i klasyczne for
rozwiązanie pętli po optymalizacji.
Działa to z dowolnymi kompilatorami zgodnymi z C ++ 11 (np. Kompilatorami takimi jak gcc-4.9.4
) i nadal tworzy prawie identyczny zestaw z podstawowym for
odpowiednikiem -loop.
Uwaga: Funkcja iota
pomocnicza służy tylko do zapewnienia parzystości funkcji w rozwiązaniu C ++ 20 std::views::iota
; ale realistycznie, możesz również bezpośrednio skonstruować iota_range{...}
zamiast dzwonić iota(...)
. Ten pierwszy przedstawia po prostu łatwą ścieżkę aktualizacji, jeśli użytkownik chce przejść na C ++ 20 w przyszłości.