如何创建隐藏载体的多层,并公开它作为一个单一的范围内Boost.Range? [英] How to create a Boost.Range that hides multiple layers of vectors and exposes it as a single Range?
问题描述
我有一个旧的类层次结构,我不能修改。由于外部库的要求,我需要定义Boost.Ranges的线路和环,其中两个只在单次运行暴露点(即它应该,无论是线路和环,是点的Boost.Range)
伪code来说明:
线L1 =行{{1.0,2.0},{3.0,4.0},{5.0,6.0}} //初始化3分线
线L2 =行{{7.0,8.0},{9.0,10.0},{11.0,12.0}} //初始化3分线自动点亮=的boost ::开始(L1); //指向点{} 1.0,2.0
++点燃; //指向点{} 3.0,4.0环R1 = {环L1,L2} //初始化戒指两条线汽车RIT =提振::开始(R1); //指向点{} 1.0,2.0
RIT ++; //指向点{} 3.0,4.0
RIT ++; //指向点{} 5.0,6.0
RIT ++; //指向点{} 7.0,8.0
RIT ++; //指向点{} 9.0,10.0
//等等...
该生产线是很容易的,因为点被直接存储(我这样做成功地与Boost.Range的看到的例子)。但是,我不知道如何与环做到这一点,因为我需要直接到各行的积分。
类Point
{
上市:
双X,Y;
}班线
{
上市:
的std ::矢量<点和GT;点;
}下课铃声
{
上市:
的std ::矢量<直线和GT;线;
}
您需要<一个href=\"http://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/extending.html\">extend Boost.Range使其能够识别戒指作为有效范围。但在此之前,你可以做到这一点,你需要定义一个平坦矢&lt自定义迭代器;矢量&lt; T&GT;方式&gt;
成一维的范围
本例使用<一个href=\"http://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/extending/method_2.html\">Method 2 延长Boost.Range。它还使用<一个href=\"http://www.boost.org/doc/libs/release/libs/iterator/doc/iterator_facade.html\"><$c$c>boost::iterator_facade$c$c>以方便编写自定义的迭代器,并假定迭代器只需要支持向前遍历。
的#include&LT;&iostream的GT;
#包括LT&;矢量&GT;
#包括LT&;升压/转让/ STD / vector.hpp&GT; //为运营商+ =()'
#包括LT&;升压/ foreach.hpp&GT;
#包括LT&;升压/迭代器/ iterator_facade.hpp&GT;
#包括LT&;升压/ range.hpp&GT;结构点
{
点(双X,双Y):X(X),Y(Y){}
双X,Y;
};结构线{性病::矢量&lt;点和GT;点;};环结构{性病::矢量&lt;直线和GT;线;};
/ *自定义迭代器类型的拉平二维数组一维数组* /
模板&LT; I类,//线迭代器类型
R级//点的引用类型
&GT;
类RingIteratorImpl:公众的boost :: iterator_facade&LT;
RingIteratorImpl&LT; I,R&gt;中点,提振:: forward_traversal_tag,R&GT;
{
上市:
RingIteratorImpl():lineIter_(0),pointIndex_(0){} 明确RingIteratorImpl(我lineIter)
:lineIter_(lineIter),pointIndex_(0){}私人的:
友元类的boost :: iterator_core_access; 无效增量()
{
++ pointIndex_;
如果(pointIndex_&GT = lineIter _-&GT; points.size())
{
++ lineIter_;
pointIndex_ = 0;
}
} 布尔等于(常量RingIteratorImpl&安培;其他)常量
{
回报(lineIter_ == other.lineIter_)及和放大器;
(pointIndex_ == other.pointIndex_);
} - [R反引用()const的{返回lineIter _-&GT;点[pointIndex_];} 我lineIter_;
为size_t pointIndex_;
};typedef的RingIteratorImpl&LT;的std ::矢量&lt;&线GT; ::迭代器,点和放大器;&GT; RingIterator;
typedef的RingIteratorImpl&LT;的std ::矢量&lt;&线GT; ::为const_iterator,常量点和放大器;&GT;
ConstRingIterator;名字空间boost
{
//专营元函数。我们必须包括range.hpp头。
//我们必须打开'助推'命名空间。 模板&LT;&GT;
结构range_mutable_iterator&LT;环&GT; {的typedef RingIterator类型; }; 模板&LT;&GT;
结构range_const_iterator&LT;环&GT; {的typedef ConstRingIterator类型; };} //命名空间升压
//要求的范围功能。这些都要在同一个命名空间中定义
//为戒。内嵌RingIterator RANGE_BEGIN(环与放; R)
{返回RingIterator(r.lines.begin());}内嵌ConstRingIterator RANGE_BEGIN(常量环和放大器; R)
{返回ConstRingIterator(r.lines.begin());}内嵌RingIterator RANGE_END(环与放; R)
{返回RingIterator(r.lines.end());}内嵌ConstRingIterator RANGE_END(常量环和放大器; R)
{返回ConstRingIterator(r.lines.end());}
诠释的main()
{
线L1,L2;
环环; {
使用空间boost ::分配; //把'操作符+ =()'变成范围
的typedef 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;
} // Foreach源升压对待戒指作为升压范围。
BOOST_FOREACH(P点,环)
{
性病::法院LT&;&LT; (&所述;&所述; p.x&所述;&下;,&所述;&所述; p.y&所述;&下;);
}
性病::法院LT&;&LT; \\ n;
}
我得到以下的输出:
(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屋!