C++实现迭代器自定义矩阵类

问题描述:

我目前正在为教育目的和个人使用的线性代数库(自定义向量和矩阵加一些算法)。我试图实现一个列迭代器,一个遍历Matrix矩阵的指定列的迭代器。C++实现迭代器自定义矩阵类

这里是矢量类的代码示例(在其上矩阵类是建立在):

template<class T> 
class MVector 
{ 
    std::vector<T> data; 

public: 

    explicit MVector(const std::size_t& n) :data(n) {} 
    explicit MVector(std::size_t&& n) :data(n) {} 

    typename std::vector<T>::iterator Begin(){ 
     return data.begin(); 
    } 

    typename std::vector<T>::iterator End(){ 
     return data.end(); 
    } 

    // many more functions and overloaded operators 
    // end of class 
}; 

矩阵类基于该载体(或对于这个问题的标准::矢量) ,看起来像:

template<class T, std::size_t rowsize, std::size_t colsize> 
class Matrix 
{ 

private: 

    // Data is stored in a MVector, a modified std::vector 
    MVector<T> matrix; 

    // size of row dimension of the matrix 
    std::size_t row_dim;     

    // size of row dimension of the matrix 
    std::size_t column_dim; 

public: 

    Matrix(std::initializer_list<T> il) :matrix(il), 
            row_dim(rowsize), column_dim(colsize){}  
    //other constructors... 

    // iterator 
    typename std::vector<T>::iterator Begin(std::size_t row = 0){ 
     return matrix.Begin()+index(row,0); 
    } 

    typename std::vector<T>::iterator End(std::size_t row = rowsize){ 
     return matrix.Begin()+index(row,0); 

    // index (convenience) function to access elements of the matrix via some_matrix(i,j) 
    std::size_t index(std::size_t r, std::size_t c) const { 
     return r*cols()+c; 
    } 

    // this is exactly what I want the iterator to do: 
    // only without creating and returning an object. 

    // get c'th column 
    // slicing is possible from both ends and by "jumping" over elements 
    // @ param "begin" - starts at the n'th element 
    // @ param "end" - subtracts m from from the last element. 
    // @ param "by" - selects every n'th column 
    MVector<T> get_column(std::size_t c, std::size_t begin = 0, 
          std::size_t end = 0, std::size_t by = 1) const{ 
     assert(c < cols() && end < rows()); 
     MVector<T> columns; 
     for (std::size_t i = index(begin, c); i < index(rows()-end,c); i+=by*cols()) { 
      columns.addTo(matrix[i]); 
     } 
     return columns;     
    } 

// end of class 
}; 

所以,迭代行工作正常,所有我需要做的就是:

int main{ 

Matrix<int, 3, 2> a = {1,2,3,4,5,6}; 
for (std::vector<int>::iterator iter = a.Begin(1); iter != a.End(2); iter++) { 
    std::cout << *iter << " "; 
} 

std::cout << endl; 
return 0; 
} 

bash-3.2$ ./main 
3 4 

这正是我想要的。但是,遍历列不适用于该方法。因此,我寻找其他解决方案,并发现这篇文章听起来非常类似于我的问题和情况,但我无法推断出问题的解决方案。

其他建议指出Boost库迭代器:特别是:

boost::adaptors::stride(rng, n) 
boost::adaptors::slice(rng, n, m) 

根据需要这的确提供了非常相似的结果。但我的get_column函数也是如此。但是我不想创建一个新对象。这是推动功能的作用。从文档“返回:基于rng的新范围,遍历以n为单位执行”。

因此,似乎迭代器不知道何时停止。

所以,我回到了第一个方法:如何返回迭代器,它遍历Matrix存储为矢量的列?

+1

[OT]:无需为size_t指定const左值引用和右值引用,只要执行'MVector(std :: size_t n)' – Jarod42 2014-10-09 16:06:13

+2

恐怕不创建具有重载增量和解引用操作符的迭代器对象。无关:如果你的矩阵大小合理地小,并且编译时常量(如模板参数),你可能会通过在你的矩阵对象中嵌入一个固定大小的数组来获得性能,而不是通过'的std :: VECTOR'。 – 5gon12eder 2014-10-09 16:14:34

+1

有什么可以阻止你使用[Boost.uBLAS](http:// www。boost.org/doc/libs/1_56_0/libs/numeric/ublas/doc/index.htm)? – 2014-10-09 18:35:26

我找到了解决问题的办法。它的组合:

这样的:Get each nth element of iterator range 这:http://www.codeproject.com/Questions/331444/How-to-use-boost-filter-iterator-as-a-class-member

在尽头,有助推周围没有办法。解决方案非常简单,如下所示:

template<class U> 
struct EveryNth { 
    bool operator()(const U&) { return m_count++ % N == 0; } 
    EveryNth(std::size_t i) : m_count(0), N(i) {} 
private: 
    int m_count; 
    std::size_t N; 
}; 

class Matrix{ 
// code here 

    typedef boost::filter_iterator<EveryNth<T>, 
           typename std::vector<T>::iterator> FilterIter; 

    FilterIter begin_jump(std::size_t i){ 
     return boost::make_filter_iterator<EveryNth<T> >(EveryNth<T>(i), data.begin(),  data.end()); 
    } 

    FilterIter end_jump(std::size_t i){ 
     return boost::make_filter_iterator<EveryNth<T> >(EveryNth<T>(i), data.end(), data.end()); 
    } 

};

和主:

int main(int argc, char *argv[]){ 

    std::vector<int> b = {1,2,3,4,5,6,7,8,9}; 
    MVector<int> a = MVector<int>(b); 
    for_each(a.begin_jump(2), a.end_jump(2), 
      [](int i){std::cout << i << " " ;} 
     ); 

    std::cout << std::endl; 
    return 0; 
} 

bash-3.2$ ./main 
1 3 5 7 9 

或使用a.begin_jump(3),而不是两个:

bash-3.2$ ./main 
1 4 7 

这正是预期的结果。