如何创建Boost.Range隐藏多层向量和暴露它作为一个单一的范围? [英] How to create a Boost.Range that hides multiple layers of vectors and exposes it as a single Range?

查看:229
本文介绍了如何创建Boost.Range隐藏多层向量和暴露它作为一个单一的范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个遗留的类层次结构,我不能修改。由于需要一个外部库,我需要为Line和Ring定义Boost.Ranges,其中两者仅在一个运行中暴露点(即,它们对于Line和Ring都应该是Boost.Range的Points)



伪代码说明:

 行l1 =行{{1.0,2.0},{3.0,4.0},{5.0,6.0}} //带有三个点的初始行
行l2 =行{{7.0,8.0},{9.0,10.0},{11.0, 12.0}} //初始化有三个点的行

auto lit = boost :: begin(l1); //指向Point {1.0,2.0}
++ lit; //指向Point {3.0,4.0}

Ring r1 = Ring {l1,l2} // init Ring with two Lines

auto rit = boost :: begin (r1)。 //指向Point {1.0,2.0}
++ rit; //指向Point {3.0,4.0}
++ rit; //指向Point {5.0,6.0}
++ rit; //指向Point {7.0,8.0}
++ rit; //指向Point {9.0,10.0}
//等...

Line很容易,因为Points直接存储(我已经成功地使用Boost.Range 查看示例)。但是,我不知道如何使用Ring,因为我需要直接到达每一行的点。

  class Point 
{
public:
double x,y;
}

class Line
{
public:
std :: vector< Point>点数;
}

class Ring
{
public:
std :: vector< Line>线;
}


解决方案

=http://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/extending.html> extend Boost.Range,以便它将Ring识别为有效范围。但在你可以做到之前,你需要定义一个自定义的迭代器,使一个向量<向量< T> < b>< a href =http://www.boost.org/doc/libs。

/release/libs/range/doc/html/range/reference/extending/method_2.html>方法2 扩展Boost.Range。它还使用 boost :: iterator_facade 以方便编写自定义迭代器,并假设迭代器只需要支持向前遍历。

  include< iostream> 
#include< vector>
#include< boost / assign / std / vector.hpp> // for'operator + =()'
#include& lt; boost / foreach.hpp>
#include< boost / iterator / iterator_facade.hpp>
#include< boost / range.hpp>

struct Point
{
点(double x,double y):x(x),y​​(y){}
double x,y;
};

struct Line {std :: vector< Point> points;};

struct Ring {std :: vector< Line> lines;};


/ *自定义迭代器类型,将2D数组平面化为1D数组* /
template< class I,//行迭代器类型
class R / /点引用类型
>
class RingIteratorImpl:public boost :: iterator_facade<
RingIteratorImpl< I,R>,Point,boost :: forward_traversal_tag,R>
{
public:
RingIteratorImpl():lineIter_(0),pointIndex_(0){}

显式RingIteratorImpl(I lineIter)
:lineIter_ (lineIter),pointIndex_(0){}

private:
friend class boost :: iterator_core_access;

void increment()
{
++ pointIndex_;
if(pointIndex_> = lineIter _-> points.size())
{
++ lineIter_;
pointIndex_ = 0;
}
}

bool equal(const RingIteratorImpl& other)const
{
return(lineIter_ == other.lineIter_)&&
(pointIndex_ == other.pointIndex_);
}

R dereference()const {return lineIter _-> points [pointIndex_];}

I lineIter_;
size_t pointIndex_;
};

typedef RingIteratorImpl< std :: vector< Line> :: iterator,Point&> RingIterator;
typedef RingIteratorImpl< std :: vector< Line> :: const_iterator,const Point&>
ConstRingIterator;

命名空间boost
{
//专门化元函数。我们必须包括range.hpp头。
//我们必须打开boost命名空间。

模板<>
struct range_mutable_iterator< Ring> {typedef RingIterator type; };

模板<>
struct range_const_iterator< Ring> {typedef ConstRingIterator type; };

} //命名空间'boost'


//必需的Range函数。这些应该在相同的命名空间
//中定义为Ring。

inline RingIterator range_begin(Ring& r)
{return RingIterator(r.lines.begin());}

inline ConstRingIterator range_begin(const Ring& r )
{return ConstRingIterator(r.lines.begin());}

inline RingIterator range_end(Ring& r)
{return RingIterator(r.lines.end );}

inline ConstRingIterator range_end(const Ring& r)
{return ConstRingIterator(r.lines.end());}


int main()
{
Line l1,l2;
戒指;

{
使用命名空间boost :: assign; // bring'operator + =()'into scope
typedef Point P;
l1.points + = P(1.1,1.2),P(1.3,1.4),P(1.5,1.6);
l2.points + = P(2.1,2.2),P(2.3,2.4),P(2.5,2.6);
ring.lines + = l1,l2;
}

// Boost Foreach将戒指视为Boost范围。
BOOST_FOREACH(Point p,ring)
{
std :: cout< (<<< p.x<<,<< p.y<<);
}
std :: cout<< \\\
;
}

我得到以下输出:

 (1.1,1.2)(1.3,1.4)(1.5,1.6)(2.1,2.2)(2.3,2.4)(2.5,2.6)


I have a legacy class hierarchy which I can not modify. Because of requirements of an external library, I need to define Boost.Ranges for the Line and Ring, where both only expose the points in a single run (i.e. it should, both for Line and Ring, be a Boost.Range of Points).

Pseudo-code to illustrate:

Line l1 = Line{{1.0,2.0},{3.0,4.0},{5.0,6.0}} // init Line with three Points
Line l2 = Line{{7.0,8.0},{9.0,10.0},{11.0,12.0}} // init Line with three Points

auto lit = boost::begin(l1); // points to the Point{1.0,2.0}
++lit; // points to the Point{3.0,4.0}

Ring r1 = Ring{l1,l2} // init Ring with two Lines

auto rit = boost::begin(r1); // points to the Point{1.0,2.0}
++rit; // points to the Point{3.0,4.0}
++rit; // points to the Point{5.0,6.0}
++rit; // points to the Point{7.0,8.0}
++rit; // points to the Point{9.0,10.0}
// etc...

The Line is easy, since the Points are stored directly (I have done this successfully with Boost.Range see the example). However, I don't know how to do this with Ring, since I need to get to each line's points directly.

class Point 
{
  public:
  double x, y;
}

class Line
{
  public:
  std::vector<Point> points;
}

class Ring
{
  public:
  std::vector<Line> lines;
}

解决方案

You need to extend Boost.Range so that it recognizes Ring as a valid range. But before you can do that, you need to define a custom iterator that flattens a vector< vector<T> > into a 1D range.

This example uses Method 2 to extend Boost.Range. It also uses boost::iterator_facade to facilitate writing a custom iterator, and assumes that the iterator only needs to support forward traversal.

#include <iostream>
#include <vector>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/foreach.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range.hpp>

struct Point
{
    Point(double x, double y) : x(x), y(y) {}
    double x, y;
};

struct Line {std::vector<Point> points;};

struct Ring {std::vector<Line> lines;};


/* Custom iterator type that flattens a 2D array into a 1D array */
template <class I, // Line iterator type
          class R  // Point reference type
         >
class RingIteratorImpl : public boost::iterator_facade<
        RingIteratorImpl<I,R>, Point, boost::forward_traversal_tag, R>
{
public:
    RingIteratorImpl() : lineIter_(0), pointIndex_(0) {}

    explicit RingIteratorImpl(I lineIter)
    :   lineIter_(lineIter), pointIndex_(0) {}

private:
    friend class boost::iterator_core_access;

    void increment()
    {
        ++pointIndex_;
        if (pointIndex_ >= lineIter_->points.size())
        {
            ++lineIter_;
            pointIndex_ = 0;
        }
    }

    bool equal(const RingIteratorImpl& other) const
    {
        return (lineIter_ == other.lineIter_) &&
               (pointIndex_ == other.pointIndex_);
    }

    R dereference() const {return lineIter_->points[pointIndex_];}

    I lineIter_;
    size_t pointIndex_;
};

typedef RingIteratorImpl<std::vector<Line>::iterator, Point&> RingIterator;
typedef RingIteratorImpl<std::vector<Line>::const_iterator, const Point&>
        ConstRingIterator;

namespace boost
{
    // Specialize metafunctions. We must include the range.hpp header.
    // We must open the 'boost' namespace.

    template <>
    struct range_mutable_iterator<Ring> { typedef RingIterator type; };

    template<>
    struct range_const_iterator<Ring> { typedef ConstRingIterator type; };

} // namespace 'boost'


// The required Range functions. These should be defined in the same namespace
// as Ring.

inline RingIterator range_begin(Ring& r)
    {return RingIterator(r.lines.begin());}

inline ConstRingIterator range_begin(const Ring& r)
    {return ConstRingIterator(r.lines.begin());}

inline RingIterator range_end(Ring& r)
    {return RingIterator(r.lines.end());}

inline ConstRingIterator range_end(const Ring& r)
    {return ConstRingIterator(r.lines.end());}


int main()
{
    Line l1, l2;
    Ring ring;

    {
        using namespace boost::assign; // bring 'operator+=()' into scope
        typedef Point P;
        l1.points += P(1.1,1.2), P(1.3,1.4), P(1.5,1.6);
        l2.points += P(2.1,2.2), P(2.3,2.4), P(2.5,2.6);
        ring.lines += l1, l2;
    }

    // Boost Foreach treats ring as a Boost Range.
    BOOST_FOREACH(Point p, ring)
    {
        std::cout << "(" << p.x << ", " << p.y << ") ";
    }
    std::cout << "\n";
}

I get the following output:

(1.1, 1.2) (1.3, 1.4) (1.5, 1.6) (2.1, 2.2) (2.3, 2.4) (2.5, 2.6) 

这篇关于如何创建Boost.Range隐藏多层向量和暴露它作为一个单一的范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆