2011-07-05 5 views
0

J'ai une liste std :: de type Foo * et une autre de type Bar * de taille inégale. Les deux types implémentent un système de positionnement qui permet de trier la liste par coordonnée z pour l'ordre de tirage (en fait, un point avec des valeurs x, y, z avec une valeur inférieure à la valeur de z).Combinaison de deux listes std :: de types différents: Possible?

Outre ce qui précède, ils sont complètement différents. Existe-t-il un moyen de combiner les listes afin que je puisse comparer TOUTES les valeurs z les unes contre les autres au lieu de leurs propres types?

À l'heure actuelle, par exemple, tous les foos sont triés ou toutes les barres sont triées; alors soit tous les foos sont tirés, soit toutes les barres sont tirées. Cela fait que même si une barre a un z inférieur à un Foo, elle sera dessinée en haut. De toute évidence pas la conséquence voulue. En tapant ceci, j'ai eu une révélation, est-ce que le traitement en parallèle fonctionnerait? Trier chaque liste séparément, puis alterner les dessiner, Foo, Bar, Foo, Bar, etc. ou cela entraînerait-il le même problème? Certains dessinant au-dessus des autres indépendamment de la valeur z?

Merci.

+1

I pense que ton épiphanie fonctionnerait bien ... garde un itérateur séparé pour chaque liste, et dessine-et-alors-itère toujours sur la liste dont l''élément courant' a la valeur Z la plus basse. Répétez jusqu'à ce que vous avez atteint la fin des deux listes. Et voilà. –

Répondre

5

Vous pouvez essayer d'avoir les deux types héritent d'une base qui comprend la position, peut-être avec un 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(); 
} 

Si vous souhaitez conserver les listes distinctes, alternant entre le dessin et FooBar ne fonctionnera pas si deux des Foo seraient venus avant un Bar.

Mais vous pensez sur la bonne voie. Vous pouvez trier individuellement puis fusionner les deux listes en dessin:

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

Vous pouvez également utiliser une variante, si vous voulez garder seulement une liste unique, mais ont deux types complètement séparés:

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

N'avait pas eu l'occasion de le tester jusqu'à maintenant, le tri individuel et la fusion tout en dessinait très bien! : D Merci pour la perspicacité. – Casey

Questions connexes