Skip to content

Instantly share code, notes, and snippets.

@klmr
Created September 2, 2012 15:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save klmr/3600202 to your computer and use it in GitHub Desktop.
Save klmr/3600202 to your computer and use it in GitHub Desktop.
Range-based for in C++
#ifndef UTIL_LANG_RANGE_HPP
#define UTIL_LANG_RANGE_HPP
#include <iterator>
namespace util { namespace lang {
namespace detail {
template <typename T>
struct range_iter_base : std::iterator<std::input_iterator_tag, T> {
range_iter_base(T current) : current(current) { }
T operator *() const { return current; }
T const* operator ->() const { return &current; }
range_iter_base& operator ++() {
++current;
return *this;
}
range_iter_base operator ++(int) {
auto copy = *this;
++*this;
return copy;
}
bool operator ==(range_iter_base const& other) const {
return current == other.current;
}
bool operator !=(range_iter_base const& other) const {
return not (*this == other);
}
protected:
T current;
};
} // namespace detail
template <typename T>
struct range_proxy {
struct iter : detail::range_iter_base<T> {
iter(T current) : detail::range_iter_base<T>(current) { }
};
struct step_range_proxy {
struct iter : detail::range_iter_base<T> {
iter(T current, T step)
: detail::range_iter_base<T>(current), step(step) { }
using detail::range_iter_base<T>::current;
iter& operator ++() {
current += step;
return *this;
}
iter operator ++(int) {
auto copy = *this;
++*this;
return copy;
}
private:
T step;
};
step_range_proxy(T begin, T end, T step)
: begin_(begin, step), end_(end, step) { }
iter begin() const { return begin_; }
iter end() const { return end_; }
private:
iter begin_;
iter end_;
};
range_proxy(T begin, T end) : begin_(begin), end_(end) { }
step_range_proxy step(T step) {
return step_range_proxy(*begin_, *end_, step);
}
iter begin() const { return begin_; }
iter end() const { return end_; }
private:
iter begin_;
iter end_;
};
template <typename T>
struct infinite_range_proxy {
struct iter : detail::range_iter_base<T> {
iter(T current = T()) : detail::range_iter_base<T>(current) { }
bool operator ==(iter const&) const { return false; }
bool operator !=(iter const&) const { return true; }
};
struct step_range_proxy {
struct iter : detail::range_iter_base<T> {
iter(T current = T(), T step = T())
: detail::range_iter_base<T>(current), step(step) { }
using detail::range_iter_base<T>::current;
iter& operator ++() {
current += step;
return *this;
}
iter operator ++(int) {
auto copy = *this;
++*this;
return copy;
}
bool operator ==(iter const&) const { return false; }
bool operator !=(iter const&) const { return true; }
private:
T step;
};
step_range_proxy(T begin, T step) : begin_(begin, step) { }
iter begin() const { return begin_; }
iter end() const { return iter(); }
private:
iter begin_;
};
infinite_range_proxy(T begin) : begin_(begin) { }
step_range_proxy step(T step) {
return step_range_proxy(*begin_, step);
}
iter begin() const { return begin_; }
iter end() const { return iter(); }
private:
iter begin_;
};
template <typename T>
range_proxy<T> range(T begin, T end) {
return range_proxy<T>(begin, end);
}
template <typename T>
infinite_range_proxy<T> range(T begin) {
return infinite_range_proxy<T>(begin);
}
} } // namespace util::lang
#endif // ndef UTIL_LANG_RANGE_HPP
#include <iostream>
#include "range.hpp"
using std::cout;
using util::lang::range;
int main() {
for (auto const i : range(1, 5))
cout << i << "\n";
for (auto const u : range(0u))
if (u == 3u) break;
else cout << u << "\n";
for (auto const c : range('a', 'd'))
cout << c << "\n";
for (auto const u : range(20u, 30u).step(2u))
cout << u << "\n";
for (auto const i : range(100).step(-3))
if (i < 90) break;
else cout << i << "\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment