2013-03-02 6 views
2

1D 배열 (템플릿으로 표시)로 표시되는 모눈 인 컨테이너를 디자인하고 있습니다. 여기에 코드 추출물을 게시 할 예정입니다. 실제로 더 많은 코드가 있습니다. 로봇 애플리케이션에서 회전하는 점유 격자로 사용되며 각 셀은 세계의 작은 영역을 나타냅니다. 내가 그 그리드 자주 할사용자 지정 컨테이너에 대한 사용자 지정 반복자

한 작업이 모든 셀을 통과하며 자신의 세계를 검색하는 것입니다 좌표 :

for(unsigned r=0; r<mygrid.rows_; ++r) { 
    for(unsigned c=0; c<mygrid.cols_; ++c) { 
    cell = mygrid.getRC(r,c); 
    mygrid.rcToXY(r,c,&x,&y); 
    } 
} 

나는 상점보다 반복자이 모든 싶은 : 셀을, 그 rc 좌표와 그 xy 좌표.

for(Grid<CellType>::const_iterator it=mygrid.begin(); it!=mygrid.end(); ++it) { 
    cell = *it; 
    printf("%d %d %f %f\n", it.r(), it.c(), it.x(), it.y()); 
} 

온라인으로 많은 답변과 튜토리얼을 작성한 후 작동하는 다음 구현을 생각해 냈습니다. 그러나 그것은 나에게 조금 서투른 것처럼 보이고, 학문을 위해서 나는 그것을 더 좋아 보이게하고 싶습니다. 또한 STL 호환성도 좋습니다.

template <class G, typename C> 
class base_iterator 
{ 
private: 
    G* grid_; 
    C* cell_; 
    unsigned r_, c_; // local 
    double x_, y_; 

// this should be private with access for friends (Grid) only 
// but I can't make it work 
public: 
    base_iterator(G* grid, unsigned r, unsigned c) : grid_(grid), r_(r), c_(c) 
    { 
    cell_ = (r<grid->rows_ && c<grid->cols_) ? &grid_->getRC(r,c) : 0; 
    grid_->rcToXY(r,c,&x_,&y_); 
    } 


public: 
    base_iterator() : grid_(0) { } 

    // used to cast an iterator to a const_iterator 
    template <class G2, typename C2> 
    base_iterator(const base_iterator<G2,C2>& other) 
    { 
    grid_ = other.grid(); 
    cell_ = & other.cell(); 
    r_ = other.r(); 
    c_ = other.c(); 
    x_ = other.x(); 
    y_ = other.y(); 
    } 

    // this should be private with access for friends only 
    G* grid() const { return grid_; } 

    C& cell() { return *cell_; } 
    const C& cell() const { return *cell_; } 
    unsigned r() const { return r_; } 
    unsigned c() const { return c_; } 
    double x() const { return x_; } 
    double y() const { return y_; } 

    C* operator->() { return cell_; } 
    const C* operator->() const { return cell_; } 

    C& operator*() { return *cell_; } 
    const C& operator*() const { return *cell_; } 

    //prefix 
    base_iterator & operator++() 
    { 
    // my iteration logic here which needs access to grid 
    // in order to find the number of rows, etc. 
    return *this; 
    } 

    //postfix 
    base_iterator operator++(int) 
    { 
    base_iterator it(*this); // make a copy for result 
    ++(*this);    // Now use the prefix version to do the work 
    return it;   // return the copy (the old) value. 
    } 

    template <class G2, typename C2> 
    bool operator==(const base_iterator<G2,C2> & other) const 
    { 
    return cell_ == &other.cell(); 
    } 

    template <class G2, typename C2> 
    bool operator!=(const base_iterator<G2,C2>& other) const 
    { return cell_!=other.cell(); } 
}; 

그리고 내 그리드 클래스 :

typedef base_iterator<Grid<T>,T> iterator; 
    typedef base_iterator<Grid<T> const, T const> const_iterator; 

    iterator begin() { return iterator(this,0,0); } 
    iterator end() { return iterator(this,rows_,cols_); } 

    const_iterator begin() const { return const_iterator(this,0,0); } 
    const_iterator end() const { return const_iterator(this,rows_,cols_); } 

다시 말하지만,이 작품,하지만 난 그게 조금 서투른 느낌 (반복자 코드의 주석을 참조), 내가하고 싶습니다 내가 그것을 향상시킬 수있는 방법을 안다. 부스트 반복기 외관이나 어댑터를 사용하는 것에 대한 수많은 게시물을 보았지만이를 필자의 경우에 적용하는 방법을 알 수 없었다.

답변

1

글쎄 나는 하나의 해결책을 발견했다. 다음은 전체 목록입니다. 특히 클래스 선언 외부에서 구현을 수행 할 수 있으려면 다소 시간이 걸리는 까다로운 부분이 있습니다. 나는 class_iterator 클래스를 non-nested 클래스의 Grid로 만들지 않았다. 내가 여기 저기에 읽은 것에 따르면, 불가능하다고 생각한다.

#include <cstdio> 
#include <cassert> 
#include <stdexcept> 
#include <algorithm> 


template <class T> 
class Grid 
{ 
public: 
    // these should be private, with public getters... 
    double resolution_; 
    unsigned rows_, cols_; 
    int map_r0_, map_c0_; // grid coordinates of origin of map 

private: 
    T* cell_; 

public: 
    Grid(double resolution, unsigned rows, unsigned cols); 
    ~Grid() { delete[] cell_; } 

    T & getRC(unsigned r, unsigned c); 
    const T & getRC(unsigned r, unsigned c) const; 
    void rcToXY(unsigned r, unsigned c, double* x, double* y) const; 

public: 
    template <class GridType, class CellType> 
    class base_iterator : std::iterator<std::forward_iterator_tag, CellType> 
    { 
    private: 
    friend class Grid; 
    GridType* grid_; 
    CellType* cell_; 
    unsigned r_, c_; // local 
    double x_, y_; 

    base_iterator(GridType* grid, unsigned r, unsigned c); 

    public: 
    base_iterator() : grid_(0) { } 

    template <class G2, class C2> 
    base_iterator(const base_iterator<G2,C2>& other); 

    CellType& cell() { return *cell_; } 
    const CellType& cell() const { return *cell_; } 
    unsigned r() const { return r_; } 
    unsigned c() const { return c_; } 
    double x() const { return x_; } 
    double y() const { return y_; } 

    CellType* operator->() { return cell_; } 
    const CellType* operator->() const { return cell_; } 

    CellType& operator*() { return *cell_; } 
    const CellType& operator*() const { return *cell_; } 

    //prefix 
    base_iterator & operator++(); 

    //postfix 
    base_iterator operator++(int); 

    template <class G2, class C2> 
    bool operator==(const base_iterator<G2,C2> & other) const 
    { return cell_ == other.cell_; } 

    template <class G2, class C2> 
    bool operator!=(const base_iterator<G2,C2>& other) const 
    { return cell_ != other.cell_; } 
    }; 

    typedef base_iterator<Grid<T>,T> iterator; 
    typedef base_iterator<Grid<T> const, T const> const_iterator; 

    iterator begin() { return iterator(this,0,0); } 
    iterator end() { return iterator(this,rows_,0); } 

    const_iterator begin() const { return const_iterator(this,0,0); } 
    const_iterator end() const { return const_iterator(this,rows_,0); } 
}; 


template <class T> 
Grid<T>::Grid(double resolution, unsigned rows, unsigned cols) 
    : resolution_(resolution), rows_(rows), cols_(cols), map_r0_(0), map_c0_(0) 
{ 
    cell_ = new T[rows_*cols_]; 
} 

template <class T> 
T & Grid<T>::getRC(unsigned r, unsigned c) 
{ 
    if (r >= rows_ || c >= cols_) 
    throw std::runtime_error("Out of bounds"); 
    return cell_[r * cols_ + c]; 
} 

template <class T> 
const T & Grid<T>::getRC(unsigned r, unsigned c) const 
{ 
    if (r >= rows_ || c >= cols_) 
    throw std::runtime_error("Out of bounds"); 
    return cell_[r * cols_ + c]; 
} 

template <class T> 
void Grid<T>::rcToXY(unsigned r, unsigned c, double* x, double* y) const 
{ 
    *x = (map_c0_ + c + 0.5) * resolution_; 
    *y = (map_r0_ + r + 0.5) * resolution_; 
} 


template <class T> 
template <class GridType, class CellType> 
Grid<T>::base_iterator<GridType,CellType>::base_iterator(GridType* grid, unsigned r, unsigned c) 
: grid_(grid), r_(r), c_(c) 
{ 
    if(r<grid->rows_ && c<grid->cols_) { 
    cell_ = &grid_->getRC(r,c); 
    grid_->rcToXY(r,c,&x_,&y_); 
    } 
    else 
    cell_ = &grid_->getRC(grid->rows_-1,grid->cols_-1) + 1; 
} 

// beautiful triple template declaration ! 
template <class T> 
template <class GridType, class CellType> 
template <class G2, class C2> 
Grid<T>::base_iterator<GridType,CellType>::base_iterator(const Grid<T>::base_iterator<G2,C2>& other) 
{ 
    grid_ = other.grid_; 
    cell_ = other.cell_; 
    r_ = other.r(); 
    c_ = other.c(); 
    x_ = other.x(); 
    y_ = other.y(); 
} 

template <class T> 
template <class GridType, class CellType> 
Grid<T>::base_iterator<GridType,CellType> & Grid<T>::base_iterator<GridType,CellType>::operator++() 
{ 
    assert(grid_!=0); 

    if(c_==grid_->cols_-1) 
    { 
    c_ = 0; 
    x_ = (grid_->map_c0_ + 0.5) * grid_->resolution_; 
    ++r_; 
    y_ += grid_->resolution_; 
    } 
    else 
    { 
    ++c_; 
    x_ += grid_->resolution_; 
    } 
    ++cell_; 

    return *this; 
} 

template <class T> 
template <class GridType, class CellType> 
Grid<T>::base_iterator<GridType,CellType> Grid<T>::base_iterator<GridType,CellType>::operator++(int) 
{ 
    base_iterator it(*this); // make a copy for result 
    ++(*this);    // Now use the prefix version to do the work 
    return it;   // return the copy (the old) value. 
} 

void print(unsigned i) 
{ 
    printf("%d ", i); 
} 

int main() 
{ 
    Grid<unsigned> mygrid(.1,2,3); 
    unsigned ctr=0; 
    for(Grid<unsigned>::iterator it=mygrid.begin(); it!=mygrid.end(); ++it) 
    *it = ctr++; 

    ctr = 0; 
    printf("All elements: r, c, x, y, value\n"); 
    for(Grid<unsigned>::const_iterator it=mygrid.begin(); it!=mygrid.end(); ++it) { 
    assert(*it == ctr++); 
    printf("%d %d %f %f %d\n", it.r(), it.c(), it.x(), it.y(), *it); 
    } 

    printf("All elements values: "); 
    std::for_each(mygrid.begin(), mygrid.end(), print); 
    printf("\n"); 

    return 0; 
} 
관련 문제