结合两个不同类型的std ::列表:可能吗?

时间:2011-07-05 03:42:52

标签: c++ stdlist

我有一个类型为Foo *的std :: list和另一个大小不等的Bar *类型。这两种类型都实现了一个定位系统,它允许列表按z坐标排序,用于绘制顺序(实际上只是一个带有x,y,z值的点,它们的排序小于谓词函数的z值)。

除了上面提到的,它们完全不同。有没有办法组合列表,以便我可以将所有z值相互比较,而不仅仅是他们自己的类型?

现在,例如,要么对所有Foos进行排序,要么对所有条形图进行排序;然后要么绘制所有的Foos,要么绘制所有的条形图。这使得即使条形图具有比Foo低的z,它也将被绘制在顶部。显然不是预期的结果。

虽然输入这个我确实有一个顿悟,并行处理工作?分别对每个列表进行排序,然后交替绘制它们,Foo,Bar,Foo,Bar等,否则会导致同样的问题?不管z值如何,有些人都会高于其他人?

感谢。

1 个答案:

答案 0 :(得分:5)

您可以尝试让这两种类型从包含该位置的基础继承,也许使用virtual Draw()

struct Base
{
    Point pos;

    virtual ~Base() {}
    virtual void Draw() = 0;
};

struct Foo : base {};
struct Bar : base {};

std::list<Base*> list;

//...

list.sort([](Base *left, Base *right)
{
    return left->pos.z < right->pos.z;
});

for(auto iter = list.begin(), end = list.end(); iter != end; ++iter)
{
    (*iter)->Draw();
}

如果您希望将列表分开,那么如果Foo中有两个Bar位于Foo之前,则在图Barfoo_list.sort(); bar_list.sort(); auto fiter = foo_list.begin(), fend = foo_list.end(); auto biter = bar_list.begin(), bend = bar_list.end(); while(fiter != fend && biter != bend) { // draw whichever Foo or Bar is closest, and increment only that iterator. if((*fiter)->z_pos < (*biter)->z_pos) { (*fiter)->Draw(); ++fiter; } else { (*biter)->Draw(); ++biter; } } // reached the end of one of the lists. flush out whatever's left of the other. for(; fiter != fend; ++fiter) { (*fiter)->draw(); } for(; biter != bend; ++biter) { (*biter)->draw(); } 之间交替将无效。

但是你正在思考正确的方向。您可以单独排序,然后在绘制时合并两个列表:

struct visitor
{
    float operator()(Foo* f) const { return f->z_position; }
    float operator()(Bar* b) const { return b->z_position; }
};

std::list<boost::variant<Foo*, Bar*>> list;

//...

list.sort([](boost::variant<Foo*, Bar*> const &left, boost::variant<Foo*, Bar*> const &right)
{
    return apply_visitor(visitor(), left) < apply_visitor(visitor(), right);
});

for(auto iter = list.begin(), end = list.end(); iter != end; ++iter)
{
    (*iter)->Draw();
}

如果您只想保留一个列表但有两个完全不同的类型,您也可以使用变体:

{{1}}