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

Posted

技术标签:

【中文标题】c++为自定义矩阵类实现迭代器【英文标题】:c++ implementing iterators for custom matrix class 【发布时间】:2014-10-09 15:56:04 【问题描述】:

我目前正在开发用于教育目的和个人用途的线性代数库(自定义向量和矩阵以及一些算法)。我试图实现一个列迭代器,一个遍历矩阵的指定列的迭代器。

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

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
;

矩阵类基于这个向量(或者这个问题的 std::vector),看起来像:

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 

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

其他建议指向 boost 库迭代器:特别是:

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

确实提供了非常相似的结果。但我的 get_column 函数也是如此。但是我不想创建一个新对象。这就是 boost 函数的作用。来自文档“返回:基于 rng 的新范围,其中以 n 步执行遍历。”

所以看起来迭代器不知道什么时候停止。

所以我回到第一个问题:如何返回一个迭代器,它遍历存储为向量的矩阵的列?

【问题讨论】:

[OT]:size_t 不需要 const 左值引用和右值引用,只需 MVector(std::size_t n) 如果不创建具有重载增量和取消引用运算符的迭代器对象,恐怕这是不可能的。不相关:如果您的矩阵大小相当小并且编译时常量(如模板参数一样),您可能会通过在矩阵对象中嵌入一个固定大小的数组来获得性能,而不是通过 @ 从空闲存储中分配内存987654329@. 有什么东西阻止你使用Boost.uBLAS? 我开始觉得使用 stl 很舒服。每次我研究 boost 时,它在我看来就像是一种完全不同的语言,我根本无法理解它。我一整天都在研究 boost 迭代器。而且我知道有很好的概念,但我不知道如何实现它们。 @GrigoriyChudnov,好点子。文森特,看看 Boost Ublas 矩阵,它非常棒。 【参考方案1】:

我找到了解决问题的方法。它是以下各项的组合:

这个: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 

这正是预期的结果。

【讨论】:

以上是关于c++为自定义矩阵类实现迭代器的主要内容,如果未能解决你的问题,请参考以下文章

c ++速度比较迭代器与索引

C++ 迭代器iterator的实现原理

在 C++ 中为我自己的自定义向量模板类实现迭代器(类似于 STL)[重复]

设计模式--迭代器模式C++实现

OOPC++自定义类型的迭代器

C++ 迭代器:实现迭代器类时出错