I've copied some code from a C++ cookbook to implement a strided iterator. The iterator seems to work with other stl functions like copy, but won't work with sort. My guess is that it has something to do with there being some operators missing. Here's my header file for the strided iterator (From the Oreilly C++ cookbook)
#define STRIDEITER_HPP
#include <iterator>
#include <cassert>
template<class Iter_T>
class stride_iter
{
public:
// public typedefs
typedef typename std::iterator_traits<Iter_T>::value_type value_type;
typedef typename std::iterator_traits<Iter_T>::reference reference;
typedef typename std::iterator_traits<Iter_T>::difference_type difference_type;
typedef typename std::iterator_traits<Iter_T>::pointer pointer;
typedef std::random_access_iterator_tag iterator_category;
typedef stride_iter self;
// constructors
stride_iter( ) : m(NULL), step(0) { };
stride_iter(const self& x) : m(x.m), step(x.step) { }
stride_iter(Iter_T x, difference_type n) : m(x), step(n) { }
// operators
self& operator++( ) { m += step; return *this; }
self operator++(int) { self tmp = *this; m += step; return tmp; }
self& operator+=(const difference_type x) { m += (x * step); return *this; }
self& operator--( ) { m -= step; return *this; }
self operator--(int) { self tmp = *this; m -= step; return tmp; }
self& operator-=(const difference_type x) { m -= x * step; return *this; }
reference operator[](const difference_type n) { return m[n * step]; }
reference operator*( ) { return *m; }
// friend operators
friend bool operator==(const self& x, const self& y) {
assert(x.step == y.step);
return x.m == y.m;
}
friend bool operator!=(const self& x, const self& y) {
assert(x.step == y.step);
return x.m != y.m;
}
friend bool operator<(const self& x, const self& y) {
assert(x.step == y.step);
return x.m < y.m;
}
friend difference_type operator-(const self& x, const self& y) {
assert(x.step == y.step);
return (x.m - y.m) / x.step;
}
friend self operator+(const self& x, difference_type y) {
assert(x.step == y.step);
return x += (y * x.step);
}
friend self operator+(difference_type x, const self& y) {
assert(x.step == y.step);
return y += x * x.step;
}
private:
Iter_T m;
difference_type step;
};
#endif
I call is using
#include "strideiter.hpp"
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
int main( ) {
int *a;
a =(int*) malloc(10*sizeof(int));
for(int i=0; i<10; i++)
{
a[i]=10-i;
}
int skip=2;
stride_iter<int*> first(a+2, skip);
stride_iter<int*> last(a + 2+8, skip);
sort(first,last);
}
I get several errors, the first one is:
strideiter.hpp(52): error: expression must have class type
assert(x.step == y.step);
Do I need multiple implementations for +=?
Fixing operator+ and providing an operator-(self, difference_type) and it compiles fine. The RandomAccessIterator "concept" and std::sort have a vast amount of requirements, which you can find here in another question involving iterators.
friend self operator+(const self& x, difference_type y) {
// do not modify `x`, but return a modified copy
return self(x.m + (y * x.step), x.step);
// idiomatically:
// self temp(x);
// temp += y;
// return temp;
}
friend self operator+(difference_type x, const self& y) {
return y+x;
}
friend self operator-(const self& x, difference_type y) {
return self(x.m - (y * x.step), x.step);
}
For this usage:
int main( ) {
int a[10];
//a =(int*) malloc(10*sizeof(int));
for(int i=0; i<10; i++)
{
a[i]=10-i;
}
for(int e : a) std::cout << e << ", ";
std::cout << std::endl;
int skip=2;
stride_iter<int*> first(a+2, skip);
stride_iter<int*> last(a + 2+8, skip);
sort(first,last);
for(int e : a) std::cout << e << ", ";
std::cout << std::endl;
}
The output is:
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
10, 9, 2, 7, 4, 5, 6, 3, 8, 1,
Which seems reasonable to me.
The problem is that you're declaring the iterator to be
a random_access_iterator, but you're not providing the
operator+ and operator- functions.
Having said that, your iterator is playing with fire, since it
will only work if the size of the container is an exact multiple
of the stride. If you have a container with, say, 100 elements,
and you ask for a stride of 3, you'll have undefined behavior.
To be useful, your iterator will have to pick up both the start
and end of the range, so that it can avoid striding over the end
(or the beginning, when striding backwards).
Related
Following the question in Pointer to portions of array, a structure that does operations with portions of an array was proposed.
I would like to request one further question within this issue.
I would like to create a structure for blockMatrices using std::vector and would require to change the implementation of the structure for getting a 3x3 matrix out of a 4x4 matrix.
The current test case is:
#include <vector>
#include <array>
#include <iostream>
// define matrix 4x4
typedef std::array<double, 16> matrix4;
// define matrix 3x3
typedef std::array<double, 9> matrix3;
// get 3x3 matrix out of a 4x4 matrix
struct subMat
{
matrix4& matrix_;
const double& operator[](size_t index) const
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return matrix_[mapping[index]];
}
subMat (matrix4& A): matrix_(A){}
};
template <typename T>
double sum_of_elements(const T& arr)
{
double res = 0;
for (int i=0;i < 9; ++i)
{
res += arr[i];
}
return res;
}
int main(int argCount, char *args[])
{
std::vector<matrix4> myBlockMatrix(5);
for (int i=0; i < myBlockMatrix.size(); i++)
{
for (int j = 0; j<myBlockMatrix[0].size(); j++)
{
myBlockMatrix[i][j] = i*j;
}
}
for (int i = 0; i<myBlockMatrix.size(); i++)
{
std::cout << sum_of_elements(subMat(myBlockMatrix[i])) << std::endl; // this works
}
subBlockMatrix subBlock (myBlockMatrix);
for (int i = 0; i<myBlockMatrix.size(); i++)
{
std::cout << sum_of_elements(subBlock[i])) << std::endl;
}
return 0;
}
For overloading the [] operator, I have:
struct subBlockMatrix : std::vector<matrix4>
{
std::vector<matrix4>& blockMatrix_;
const matrix4& operator[](std::size_t index) const
{
static size_t mapping[] = {0, 1, 2, 4, 5, 6, 8, 9, 10};
return blockMatrix_[mapping[index]];
}
subBlockMatrix(std::vector<matrix4>& A) : blockMatrix_(A) {}
};
But this does not work...
I am having difficulty understanding how to make it work and would really appreciate the help!
Best Regards
I'd start with a matrix view, which starts with an array view.
#include <vector>
#include <iostream>
template<class T, class Size=std::size_t, class Stride=Size>
struct array_view {
array_view( T* start, Size sz, Stride s ):
b(start), length(sz), stride(s) {}
array_view( T* start, Size sz = {} ):
b(start), length(sz), stride(sz) {}
array_view() = default;
array_view( T* start, T* finish ):
array_view(start, finish-start) {}
T* begin() const { return b; }
T* end() const { return b+length; }
std::size_t size() const { return length; }
bool empty() const { return size() == 0; }
explicit operator bool() const { return b; }
T& operator[]( std::size_t i ) const { return begin()[i]; }
array_view& operator++() {
*this += 1;
return *this;
}
array_view operator++(int)& {
auto self = *this;
++this;
return self;
}
array_view& operator--() {
*this -= 1;
return *this;
}
array_view operator--(int)& {
auto self = *this;
--this;
return self;
}
array_view& operator+=(std::ptrdiff_t delta)&{
b+=delta*length;
return *this;
}
array_view& operator-=(std::ptrdiff_t delta)&{
b-=delta*length;
return *this;
}
friend array_view operator+(array_view self, std::ptrdiff_t delta) {
self += delta;
return self;
}
friend array_view operator-(array_view self, std::ptrdiff_t delta) {
self -= delta;
return self;
}
friend array_view operator+(std::ptrdiff_t delta, array_view self) {
self += delta;
return self;
}
friend array_view operator-(std::ptrdiff_t delta, array_view self) {
self -= delta;
return self;
}
// checks address, not contents
friend bool operator==(array_view const& lhs, array_view const& rhs) {
return lhs.b == rhs.b && lhs.length == rhs.length && lhs.stride == rhs.stride;
}
friend bool operator!=(array_view const& lhs, array_view const& rhs) {
return !(lhs==rhs);
}
private:
T* b = nullptr;
Size length = {};
Stride stride = {};
};
then we get a matrix_view. First we write an index_iterator for an iterator wrapper around something that is a value (like a sequence of rows or columns, or an integer):
template<class V>
struct index_iterator {
index_iterator(V v):value(v) {}
V const& operator*() const& { return value; }
V& operator*()& { return value; }
V operator*()&& { return std::move(value); }
V* operator->() { return std::addressof(value); }
V const* operator->() const { return std::addressof(value); }
friend bool operator==(index_iterator const& lhs, index_iterator const& rhs ) {
return lhs.value==rhs.value;
}
friend bool operator!=(index_iterator const& lhs, index_iterator const& rhs ) {
return lhs.value!=rhs.value;
}
index_iterator& operator++() {
++value;
return *this;
}
index_iterator operator++(int)& {
auto self = *this;
++value;
return self;
}
index_iterator& operator--() {
--value;
return *this;
}
index_iterator operator--(int)& {
auto self = *this;
--value;
return self;
}
index_iterator& operator+=( std::ptrdiff_t delta )& {
value += delta;
return *this;
}
index_iterator& operator-=( std::ptrdiff_t delta )& {
value -= delta;
return *this;
}
friend index_iterator operator+(index_iterator self, std::ptrdiff_t delta) {
self += delta;
return self;
}
friend index_iterator operator-(index_iterator self, std::ptrdiff_t delta) {
self -= delta;
return self;
}
friend index_iterator operator+(std::ptrdiff_t delta, index_iterator self) {
self += delta;
return self;
}
friend index_iterator operator-(std::ptrdiff_t delta, index_iterator self) {
self -= delta;
return self;
}
V operator[](std::size_t i)const {
return *((*this) + i);
}
private:
V value = {};
};
template<class T, class M=std::size_t, class Stride=M, class N=M>
struct matrix_view {
using row_view = array_view<T, N, Stride>;
matrix_view( T* start, M cols={}, Stride stride = {}, N rows={} ):
b(start), m(cols), s(stride), n(rows)
{}
matrix_view() = default;
index_iterator<row_view> begin() const { return {{b, n, s}}; }
index_iterator<row_view> end() const { return begin()+m; }
std::size_t size() const { return m; }
bool empty() const { return size() == 0; }
explicit operator bool() const { return b; }
row_view operator[]( std::size_t i ) const { return begin()[i]; }
private:
T* b = nullptr;
M m = {};
Stride s = {};
N n = {};
};
template<std::size_t N>
using size = std::integral_constant<std::size_t, N>;
int main(){
std::vector<int> v {00,01,02,03, 10,11,12,13, 20,21,22,23, 30,31,32,33};
matrix_view<int, size<3>, size<4>> m = v.data()+5;
for (auto col:m) {
for (auto e:col) {
std::cout << e << ",";
}
std::cout << "\n";
}
}
and then clean it up with some CRTP DRY and EBO.
But that is just me.
Live example.
I need to build an inner class iterator to work with a container class FigureOfCircles
#define T Circle
class FigureOfCircles {
private:
Circle* c;
int size;
public:
class Iterator {
protected:
T* t;
public:
explicit Iterator (T* t1 = 0) : t(t1) { }
Iterator (const Iterator& x) : t(x.t) {}
T& operator*() const { return *t; }
T* operator->() const { return t; }
Circle& operator[](const std::size_t& n) { return t[n]; }
Iterator& operator++() { ++t; return *this; }
Iterator operator++(int) { return Iterator(t++); }
Iterator& operator--() { --t; return *this; }
Iterator operator--(int) { return Iterator(t--); }
Iterator operator- (int n) { return Iterator(t - n); }
Iterator operator+ (int n) { return Iterator(t - n); }
Iterator& operator-= (int n) { t -= n; return *this; }
Iterator& operator+= (int n) { t += n; return *this; }
bool operator== (const Iterator& x) const { return t == x.t; }
bool operator!= (const Iterator& x) const { return t != x.t; }
bool operator<= (const Iterator& x) const { return t <= x.t; }
bool operator> (const Iterator& x) const { return t > x.t; }
bool operator>= (const Iterator& x) const { return t >= x.t; }
bool operator< (const Iterator& x) const { return t < x.t; }
friend int operator- (const Iterator& x, const Iterator& y) { return x.t - y.t; }
Iterator& operator= (const Iterator& x) {
if (t == x.t) exit(-6);
t = x.t;
return *this;
}
};
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = input();
}
FigureOfCircles(const FigureOfCircles& f) {
size = f.size;
c = new T[size];
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
}
~FigureOfCircles() { if (c) delete[] c; }
Circle input() {
int size = 1;
Point* arr = new Point[size];
float r, x1, y1;
cout << endl << "Введiть к-сть точок, радiус i координати центру: ";
cin >> size >> r >> x1 >> y1;
for (int i = 0; i < size; i++) {
Point tmp;
cin >> tmp;
if (tmp.GetX() == x1 && tmp.GetY() == y1) exit(-7);
if (pow(tmp.GetX() - x1, 2) + pow(tmp.GetY() - y1, 2) != r * r) exit(-8);
arr[i] = tmp;
}
return Circle(size, r, arr, x1, y1);
}
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
};
But I don’t understand what type should T be so that I can use the iterator object? If it is int, then what about
Iterator begin() { return Iterator(c); }
Iterator end() { return Iterator(c+size); }
Note:
FigureOfCircles (int sz) : size(sz) {
c = new T[size];
for (int i = 0; i < size; i++)
c[i].input();
for (Iterator i = begin(); i != end(); ++i) {
*i = T(i-begin());
}
}
...
int main () {
//...
FigureOfCircles f(2);
FigureOfCircles::Iterator i;
for (i = f.begin(); i != f.end(); i++) cout << *i << endl;
}
You have an array of Circles, pointed by c. An iterator should point to elements of this array. The simplest solution is to use a plain pointer. That is, T in your iterator should be just Circle.
If you want to use int (it should be std::ptrdiff_t), your iterator should also keep a pointer to the first element. In this particular example I don't see a reason to do it.
operator- should return the difference between pointers, std::ptrdiff_t, not Circle:
friend std::ptrdiff_t operator-(Iterator x, Iterator y) {
return x.t - y.t;
}
Take Iterator by value. It's just a single pointer, you don't need to take it by const-ref (effectively taking a pointer to a pointer).
Once you have iterators, you can use the standard library algorithms to make copies: instead of
for (Iterator i = begin(); i != end(); ++i) *i = f.c[i - begin()];
you can write
std::copy(f.begin(), f.end(), begin());
I suggest you use std::vector<Circle> instead of Circle*. Then you'll be able to borrow its iterators:
class FigureOfCircles {
private:
std::vector<Circle> c;
public:
std::vector<Circle>::iterator begin() {
c.begin();
}
std::vector<Circle>::iterator end() {
c.end();
}
};
This will also save you from writing a copy constructor and destructor.
While #Evg's answer is valid, it is not clear from your question why would even need to write your own iterator. If, instead of a pair of pointer+length members, you would use an std::vector or std::array - or even std::span which is oblivious to where you get your buffer from - you could use these classes' respective iterators instead of implementing your own.
It is only if you have some special behavior in your FigureOfCircles class - e.g. element skipping, non-standard iteration order and so on - that you really need a custom iterator.
PS - The naming is a bit awkward. If a Figure can only have Circles, then just call the class Figure. If there are Figures of something other than Circles, try: template <typename Element> class Figure { ... } and then you'll use Figure<Circle>.
Say I have a nest for loop like
for (int x = xstart; x < xend; x++){
for (int y = ystart; y < yend; y++){
for (int z = zstart; z < zend; z++){
function_doing_stuff(std::make_tuple(x, y, z));
}
}
}
and would like to transform it into
MyRange range(xstart,xend,ystart,yend, zstart,zend);
for (auto point : range){
function_doing_stuff(point);
}
How would I write the MyRange class to be as efficient as the nested for loops?
The motivation for this is to be able to use std algorithms (such as transform, accumulate, etc), and to create code that is largely dimension agnostic.
By having an iterator, it would be easy to create templated functions that operate over a range of 1d, 2d or 3d points.
Code base is currently C++14.
EDIT:
Writing clear questions is hard. I'll try to clarify.
My problem is not writing an iterator, that I can do. Instead, the problem is one of performance: Is it possible to make an iterator that is as fast as the nested for loops?
With range/v3, you may do
auto xs = ranges::view::iota(xstart, xend);
auto ys = ranges::view::iota(ystart, yend);
auto zs = ranges::view::iota(zstart, zend);
for (const auto& point : ranges::view::cartesian_product(xs, ys, zs)){
function_doing_stuff(point);
}
You can introduce your own class as
class myClass {
public:
myClass (int x, int y, int z):m_x(x) , m_y(y), m_z(z){};
private:
int m_x, m_y, m_z;
}
and then initialize a std::vector<myClass> with your triple loop
std::vector<myClass> myVec;
myVec.reserve((xend-xstart)*(yend-ystart)*(zend-zstart)); // alloc memory only once;
for (int x = ystart; x < xend; x++){
for (int y = xstart; y < yend; y++){ // I assume you have a copy paste error here
for (int z = zstart; z < zend; z++){
myVec.push_back({x,y,z})
}
}
}
Finally, you can use all the nice std algorithms with the std::vector<myClass> myVec. With the syntactic sugar
using MyRange = std::vector<MyClass>;
and
MyRange makeMyRange(int xstart, int xend, int ystart, int yend, int zstart,int zend) {
MyRange myVec;
// loop from above
return MyRange;
}
you can write
const MyRange range = makeMyRange(xstart, xend, ystart, yend, zstart, zend);
for (auto point : range){
function_doing_stuff(point);
}
With the new move semantics this wont create unneeded copies. Please note, that the interface to this function is rather bad. Perhaps rather use 3 pairs of int, denoting the x,y,z interval.
Perhaps you change the names to something meaningful (e.g.myClass could be Point).
Another option, which directly transplants whatever looping code, is to use a Coroutine. This emulates yield from Python or C#.
using point = std::tuple<int, int, int>;
using coro = boost::coroutines::asymmetric_coroutine<point>;
coro::pull_type points(
[&](coro::push_type& yield){
for (int x = xstart; x < xend; x++){
for (int y = ystart; y < yend; y++){
for (int z = zstart; z < zend; z++){
yield(std::make_tuple(x, y, z));
}
}
}
});
for(auto p : points)
function_doing_stuff(p);
Since you care about performance, you should forget about combining iterators for the foreseeable future. The central problem is that compilers cannot yet untangle the mess and figure out that there are 3 independent variables in it, much less perform any loop interchange or unrolling or fusion.
If you must use ranges, use simple ones that the compiler can see through:
for (int const x : boost::irange<int>(xstart,xend))
for (int const y : boost::irange<int>(ystart,yend))
for (int const z : boost::irange<int>(zstart,zend))
function_doing_stuff(x, y, z);
Alternatively, you can actually pass your functor and the boost ranges to a template:
template <typename Func, typename Range0, typename Range1, typename Range2>
void apply_ranges (Func func, Range0 r0, Range1 r1, Range2 r2)
{
for (auto const i0 : r0)
for (auto const i1 : r1)
for (auto const i2 : r2)
func (i0, i1, i2);
}
If you truly care about performance, then you should not contort your code with complicated ranges, because they make it harder to untangle later when you want to rewrite them in AVX intrinsics.
Here's a bare-bones implementation that does not use any advanced language features or other libraries. The performance should be pretty close to the for loop version.
#include <tuple>
class MyRange {
public:
typedef std::tuple<int, int, int> valtype;
MyRange(int xstart, int xend, int ystart, int yend, int zstart, int zend): xstart(xstart), xend(xend), ystart(ystart), yend(yend), zstart(zstart), zend(zend) {
}
class iterator {
public:
iterator(MyRange &c): me(c) {
curvalue = std::make_tuple(me.xstart, me.ystart, me.zstart);
}
iterator(MyRange &c, bool end): me(c) {
curvalue = std::make_tuple(end ? me.xend : me.xstart, me.ystart, me.zstart);
}
valtype operator*() {
return curvalue;
}
iterator &operator++() {
if (++std::get<2>(curvalue) == me.zend) {
std::get<2>(curvalue) = me.zstart;
if (++std::get<1>(curvalue) == me.yend) {
std::get<1>(curvalue) = me.ystart;
++std::get<0>(curvalue);
}
}
return *this;
}
bool operator==(const iterator &other) const {
return curvalue == other.curvalue;
}
bool operator!=(const iterator &other) const {
return curvalue != other.curvalue;
}
private:
MyRange &me;
valtype curvalue;
};
iterator begin() {
return iterator(*this);
}
iterator end() {
return iterator(*this, true);
}
private:
int xstart, xend;
int ystart, yend;
int zstart, zend;
};
And an example of usage:
#include <iostream>
void display(std::tuple<int, int, int> v) {
std::cout << "(" << std::get<0>(v) << ", " << std::get<1>(v) << ", " << std::get<2>(v) << ")\n";
}
int main() {
MyRange c(1, 4, 2, 5, 7, 9);
for (auto v: c) {
display(v);
}
}
I've left off things like const iterators, possible operator+=, decrementing, post increment, etc. They've been left as an exercise for the reader.
It stores the initial values, then increments each value in turn, rolling it back and incrementing the next when it get to the end value. It's a bit like incrementing a multi-digit number.
Using boost::iterator_facade for simplicity, you can spell out all the required members.
First we have a class that iterates N-dimensional indexes as std::array<std::size_t, N>
template<std::size_t N>
class indexes_iterator : public boost::iterator_facade<indexes_iterator, std::array<std::size_t, N>>
{
public:
template<typename... Dims>
indexes_iterator(Dims... dims) : dims{ dims... }, values{} {}
private:
friend class boost::iterator_core_access;
void increment() { advance(1); }
void decrement() { advance(-1); }
void advance(int n)
{
for (std::size_t i = 0; i < N; ++i)
{
int next = ((values[i] + n) % dims[i]);
n = (n \ dims[i]) + (next < value);
values[i] = next;
}
}
std::size_t distance(indexes_iterator const & other) const
{
std::size_t result = 0, mul = 1;
for (std::size_t i = 0; i < dims; ++i)
{
result += mul * other[i] - values[i];
mul *= ends[i];
}
}
bool equal(indexes_iterator const& other) const
{
return values == other.values;
}
std::array<std::size_t, N> & dereference() const { return values; }
std::array<std::size_t, N> ends;
std::array<std::size_t, N> values;
}
Then we use that to make something similar to a boost::zip_iterator, but instead of advancing all together we add our indexes.
template <typename... Iterators>
class product_iterator : public boost::iterator_facade<product_iterator<Iterators...>, const std::tuple<decltype(*std::declval<Iterators>())...>, boost::random_access_traversal_tag>
{
using ref = std::tuple<decltype(*std::declval<Iterators>())...>;
public:
product_iterator(Iterators ... ends) : indexes() , iterators(std::make_tuple(ends...)) {}
template <typename ... Sizes>
product_iterator(Iterators ... begins, Sizes ... sizes)
: indexes(sizes...),
iterators(begins...)
{}
private:
friend class boost::iterator_core_access;
template<std::size_t... Is>
ref dereference_impl(std::index_sequence<Is...> idxs) const
{
auto offs = offset(idxs);
return { *std::get<Is>(offs)... };
}
ref dereference() const
{
return dereference_impl(std::index_sequence_for<Iterators...>{});
}
void increment() { ++indexes; }
void decrement() { --indexes; }
void advance(int n) { indexes += n; }
template<std::size_t... Is>
std::tuple<Iterators...> offset(std::index_sequence<Is...>) const
{
auto idxs = *indexes;
return { (std::get<Is>(iterators) + std::get<Is>(idxs))... };
}
bool equal(product_iterator const & other) const
{
return offset(std::index_sequence_for<Iterators...>{})
== other.offset(std::index_sequence_for<Iterators...>{});
}
indexes_iterator<sizeof...(Iterators)> indexes;
std::tuple<Iterators...> iterators;
};
Then we wrap it up in a boost::iterator_range
template <typename... Ranges>
auto make_product_range(Ranges&&... rngs)
{
product_iterator<decltype(begin(rngs))...> b(begin(rngs)..., std::distance(std::begin(rngs), std::end(rngs))...);
product_iterator<decltype(begin(rngs))...> e(end(rngs)...);
return boost::iterator_range<product_iterator<decltype(begin(rngs))...>>(b, e);
}
int main()
{
using ranges::view::iota;
for (auto p : make_product_range(iota(xstart, xend), iota(ystart, yend), iota(zstart, zend)))
// ...
return 0;
}
See it on godbolt
Just a very simplified version that will be as efficient as a for loop:
#include <tuple>
struct iterator{
int x;
int x_start;
int x_end;
int y;
int y_start;
int y_end;
int z;
constexpr auto
operator*() const{
return std::tuple{x,y,z};
}
constexpr iterator&
operator++ [[gnu::always_inline]](){
++x;
if (x==x_end){
x=x_start;
++y;
if (y==y_end) {
++z;
y=y_start;
}
}
return *this;
}
constexpr iterator
operator++(int){
auto old=*this;
operator++();
return old;
}
};
struct sentinel{
int z_end;
friend constexpr bool
operator == (const iterator& x,const sentinel& s){
return x.z==s.z_end;
}
friend constexpr bool
operator == (const sentinel& a,const iterator& x){
return x==a;
}
friend constexpr bool
operator != (const iterator& x,const sentinel& a){
return !(x==a);
}
friend constexpr bool
operator != (const sentinel& a,const iterator& x){
return !(x==a);
}
};
struct range{
iterator start;
sentinel finish;
constexpr auto
begin() const{
return start;
}
constexpr auto
end()const{
return finish;
}
};
void func(int,int,int);
void test(const range& r){
for(auto [x,y,z]: r)
func(x,y,z);
}
void test(int x_start,int x_end,int y_start,int y_end,int z_start,int z_end){
for(int z=z_start;z<z_end;++z)
for(int y=y_start;y<y_end;++y)
for(int x=x_start;x<x_end;++x)
func(x,y,z);
}
The advantage over 1201ProgramAlarm answer is the faster test performed at each iteration thanks to the use of a sentinel.
I am trying to develop smart iterator, but even when I create a naive one it crash when I am using sort with it.
The range for loop worked well, but std::sort does not.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename I>
class it {
public:
it(I i) : i(i){}
using iterator_category = std::random_access_iterator_tag;
using value_type = typename I::value_type;
using difference_type = std::ptrdiff_t;
using pointer = typename I::pointer;
using reference = typename I::reference;
value_type &operator*() {
return *i;
}
it &operator++() {
++i;
return *this;
}
it &operator--() {
--i;
return *this;
}
bool operator!=(it a) {
return a.i != i;
}
it &operator+(std::size_t n) {
i += n;
return *this;
}
it &operator-(std::size_t n) {
i -= n;
return *this;
}
std::ptrdiff_t operator-(it a) {
return i - a.i;
}
bool operator==(it a) {
return a.i == i;
}
bool operator<(it a) {
return i < a.i;
}
private:
I i;
};
int main()
{
std::vector<int> v = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
for(auto e : v)
std::cout << e << " ";
std::cout << std::endl;
std::sort(it<decltype(v.begin())>(v.begin()), it<decltype(v.end())>(v.end()));
for(auto e : v)
std::cout << e << " ";
std::cout << std::endl;
return 0;
}
The crash happen in "clang-code" here (gdb tell me that) :
struct _Iter_less_iter
{
template<typename _Iterator1, typename _Iterator2>
_GLIBCXX14_CONSTEXPR
bool
operator()(_Iterator1 __it1, _Iterator2 __it2) const
{ return *__it1 < *__it2; }
};
It happened when it deferrence it.
Do you have an idea?
Don't know for sure what the underlying problem is, but this is definitely wrong:
it &operator+(std::size_t n) {
i += n;
return *this;
}
That operator should return a new iterator, and not modify the one it's called on. Something like this:
it operator+(std::size_t n) {
it temp = *this;
temp.i += n;
return temp;
}
Note that this returns the iterator by value, not by reference.
Same thing for operator-.
Your operator+ has the semantics of operator+=, and your operator- has the semantics of operator-=. They should not modify the iterator, but instead create a new iterator with the modified value and return that. Also, they should both accept signed values. In fact, a proper random access iterator should have both sets of operators, so just keep the functions as they are, but change the signatures.
it& operator+=(difference_type n) {
i += n;
return *this;
}
it &operator-=(difference_type n) {
i -= n;
return *this;
}
Then you can implement operator+ and operator- in terms of those. (note that these return by value, not reference, and are marked const)
it operator+(difference_type n) const {
it result = *this;
result += n;
return result;
}
it operator-(difference_type n) const {
it result = *this;
result -= n;
return result;
}
I'm trying to implement a container in C++ that uses a flat array to store the data but iterates over that data in pairs. Now I could easily change the implementation such that the container holds a vector of std::pair however I want to iterate through pairs starting at element 0 or at element 1.
To illustrate what I want to achieve, if my underlying array looks like:
1,2,3,4,5,6,7,8
I want to define two iterators, one which returns the pairs:
(1,2), (3,4), (5,6), (7,8)
and the second iterator to return the pairs:
(2,3), (4,5), (6,7)
is this possible to do while still allowing the elements of the iterator to be references of the underlying array?
It is possible to write your own iterator, which iterates over the elements. The following question shows some explanations on how that is done:
Custom Iterator in C++.
You can then return the desired values as std::pair and iterate to the next element-pair (by incrementing the counter by 2).
Boost library has got Iterator Adaptor that allows you to wrap other iterator types and change or adapt their functionality. Here's how you could use it for your purpose:
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
struct iterator :
public boost::iterator_adaptor<
iterator, // the name of our class, see docs for details
std::vector<int>::iterator, // underlying base iterator
std::pair<int&, int&>, // our value type
boost::forward_traversal_tag // the category you wish to give it
>
{
// need this to convert from vector::iterator to ours
explicit iterator(std::vector<int>::iterator i)
: iterator::iterator_adaptor_(i) {}
value_type operator*()
{
return value_type(
*base_reference(),
*(base_reference()+1)
);
}
};
Example of usage:
std::vector<int> v {1,2,3,4};
iterator it(v.begin());
++it;
(*it).first = 0; // TODO: operator->
(*it).second = 0;
for (int i : v) std::cout << i << ' '; // prints 1 0 0 4
You'll also need to override comparison to properly handle end condition, etc. Hope that helps.
Just thought I'd put in what I actually used in my code. I didn't want to use boost as suggested by #jrok but the type std::pair<int&, int&> in their answer gave me a hint of what was required.
Below is the class that I constructed which uses two iterators. A RepeatIterator that returns pairs starting on even indexes in the underlying data, and a SpacerIterator that returns pairs starting on odd indexes.
class RepeatArray {
typedef std::vector<int> storage_t;
public:
class RepeatIterator {
public:
typedef RepeatIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
RepeatIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
class SpacerIterator {
public:
typedef SpacerIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
SpacerIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
void add(int start, int end) {
positions.push_back(start);
positions.push_back(end);
}
void dump() {
for (auto i : positions) {
std::cout <<i<<",";
}
std::cout <<std::endl;
}
RepeatIterator repeatBegin(){return RepeatIterator(positions.begin());}
RepeatIterator repeatEnd(){return RepeatIterator(positions.end());}
SpacerIterator spacerBegin(){return SpacerIterator(positions.begin() + 1);}
SpacerIterator spacerEnd(){return SpacerIterator(positions.end() - 1);}
protected:
storage_t positions;
};
And then the tesing program compiled using clang++ -std=c++0x -o testRepeatArray RepeatArray.cpp
int main() {
RepeatArray r = RepeatArray();
r.add(1,3);
r.add(7,12);
std::cout<<"original:"<<std::endl;
r.dump();
std::cout << "Testing Repeat iterator:"<<std::endl;
for (RepeatArray::RepeatIterator it2 = r.repeatBegin(); it2 != r.repeatEnd(); ++it2) {
std::cout << (*it2).first <<","<< (*it2).second << std::endl;
}
std::cout << "Testing Spacer iterator:"<<std::endl;
for (RepeatArray::SpacerIterator it3 = r.spacerBegin(); it3 != r.spacerEnd(); ++it3) {
std::cout << (*it3).first <<","<< (*it3).second << std::endl;
}
std::cout<<"Testing modification:"<<std::endl;
RepeatArray::RepeatIterator it = r.repeatBegin();
(*it).first = 0;
(*it).second = 123;
r.dump();
return 0;
}