Для тех, кому нравится ответ Cigien std::views::iota
, но он не работает на C++20 или выше, довольно просто реализовать упрощенную и облегченную версию std::views::iota
совместимого класса c++11 или выше.
Все, что для этого требуется, это:
- Базовый тип LegacyInputIterator (что-то, что определяет
operator++
и operator*
), который упаковывает целочисленное значение. (например, int
)
- Некоторый класс, похожий на диапазон, который имеет
begin()
и end()
, который возвращает вышеуказанные итераторы. Это позволит ему работать в циклах for
на основе диапазона.
Упрощенная версия этого может быть:
#include <iterator>
// This is just a class that wraps an 'int' in an iterator abstraction
// Comparisons compare the underlying value, and 'operator++' just
// increments the underlying int
class counting_iterator
{
public:
// basic iterator boilerplate
using iterator_category = std::input_iterator_tag;
using value_type = int;
using reference = int;
using pointer = int*;
using difference_type = std::ptrdiff_t;
// Constructor / assignment
constexpr explicit counting_iterator(int x) : m_value{x}{}
constexpr counting_iterator(const counting_iterator&) = default;
constexpr counting_iterator& operator=(const counting_iterator&) = default;
// "Dereference" (just returns the underlying value)
constexpr reference operator*() const { return m_value; }
constexpr pointer operator->() const { return &m_value; }
// Advancing iterator (just increments the value)
constexpr counting_iterator& operator++() {
m_value++;
return (*this);
}
constexpr counting_iterator operator++(int) {
const auto copy = (*this);
++(*this);
return copy;
}
// Comparison
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;
};
// Just a holder type that defines 'begin' and 'end' for
// range-based iteration. This holds the first and last element
// (start and end of the range)
// The begin iterator is made from the first value, and the
// end iterator is made from the second 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}; }
};
// A simple helper function to return the range
// This function isn't strictly necessary, you could just construct
// the 'iota_range' directly
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 << " "; // ok
i = 42; // error
}
Который создаст такую же сборку, что и решение 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.
person
Human-Compiler
schedule
13.08.2020
while(i_copy = loop()) { }
- person stark   schedule 13.08.2020const int& i_safe = i
. Ваш компилятор должен исключать любую косвенность. - person Brian   schedule 13.08.2020i
уязвимым для тела вредоносного цикла. - person stark   schedule 13.08.2020i
, не годится? Вы хотите иметь доступ только для чтения кi
в цикле? - person cigien   schedule 13.08.2020for({int i=0; i<10; ++i}){
для этого, но никогда не имел смелости предложить это комитету по стандартам или Бьярну, когда он добросовестно работает в Morgan Stanley. Конечно, мое предложение не позволит вам даже получить доступ кi
в теле. - person Bathsheba   schedule 13.08.2020const int i
. Изменчивость индекса доступна только там, где это необходимо, и вы можете использовать ключевое словоinline
, чтобы оно не влияло на скомпилированный вывод. - person Monty Thibault   schedule 14.08.2020const
для начала. - person Konrad Rudolph   schedule 16.08.2020ì
изменяется в цикле. Если цикл большой, то его следует преобразовать в функцию. - person Phil1970   schedule 17.08.2020