Для тих, хто любить відповідь Cigien, std::views::iota
але не працює на C ++ 20 або вище, досить просто впровадити спрощену та полегшену версію std::views::iota
сумісногоc ++ 11 або вище.
Для цього потрібно лише:
- Базовий тип " LegacyInputIterator " (щось, що визначає
operator++
і operator*
), що обертає інтегральне значення (наприклад, an int
)
- Якийсь "діапазон" -подібний клас, який має
begin()
і end()
який повертає вищезазначені ітератори. Це дозволить йому працювати в for
циклах на основі діапазону
Спрощена версія цього може бути:
#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};
}
Я визначив вище, constexpr
де це підтримується, але для попередніх версій C ++, таких як C ++ 11/14, можливо, вам доведеться видалити, constexpr
де це не є законним у цих версіях.
Наведений вище шаблон дає змогу наступному коду працювати в попередній версії C ++ 20:
for (int const i : iota(0, 10))
{
std::cout << i << " ";
i = 42;
}
Що при оптимізації генерує ту саму збірку, що і рішення C ++ 20 std::views::iota
та класичне for
рішення-loop.
Це працює з будь-якими компіляторами, сумісними з C ++ 11 (наприклад, компіляторами gcc-4.9.4
), і все ще виробляє майже ідентичну збірку базовому for
аналогу-циклу.
Примітка:iota
допоміжна функція тільки для ознаки-парності з C ++ 20 std::views::iota
рішення; але реально, ви також можете безпосередньо побудувати iota_range{...}
замість того, щоб дзвонити iota(...)
. Перший просто представляє простий шлях оновлення, якщо користувач бажає перейти на C ++ 20 у майбутньому.