2014-10-09 94 views
0

我目前正在爲教育目的和個人使用的線性代數庫(自定義向量和矩陣加一些算法)。我試圖實現一個列迭代器,一個遍歷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

回答

0

我找到了解決問題的辦法。它的組合:

這樣的: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 

這正是預期的結果。