【问题标题】:Combining two std::lists of differing types: Possible?结合两个不同类型的 std::lists:可能吗?
【发布时间】:2023-03-11 11:30:01
【问题描述】:

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

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

现在,例如,要么所有 Foo 都已排序,要么所有 Bars 都已排序;然后要么绘制所有 Foos,要么绘制所有 Bars。这使得即使 Bar 的 z 比 Foo 低,它也会被绘制在顶部。显然不是预期的结果。

在输入此内容时,我确实顿悟了,并行处理会起作用吗?分别对每个列表进行排序,然后交替绘制它们,Foo、Bar、Foo、Bar 等,还是会导致同样的问题?不管z值如何,有些画在其他上面?

谢谢。

【问题讨论】:

  • 我认为你的顿悟会很好用......为每个列表保留一个单独的迭代器,并始终在“当前项目”具有较低 Z 值的列表上绘制然后迭代。重复直到你到达两个列表的末尾。等等。

标签: c++ stdlist


【解决方案1】:

您可以尝试让这两种类型都从包含该位置的基类继承,也许使用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 之前,则交替绘制FooBar 将不起作用。

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

foo_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();
}

【讨论】:

  • 直到现在还没有机会测试它,单独排序并在绘图时合并效果很好! :D 感谢您的洞察力。
猜你喜欢
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多