OVH Cloud OVH Cloud

multi method - first fit

2 réponses
Avatar
Benoit Rousseau
Bonjour,

Pour programmer la collision entre 2 objects d'une arène, je comptais
utiliser un dispatcher. Scott Meyer décrit (je n'ai pas le livre donc je
fausse peut être ses propos) un dispatcher utilisant un map et une pair
de typeinfo comme clef.
Je trouve cette méthode très souple, mais pas assez. En effet, la
collision d'un robot avec un autre robot est la seule nécessitant de
connaitre le type des deux objects :

map[ <Robot, Robot> ] = collide( Robot&, Robot& );

et une colision entre robot et un autre objet dans l'arene se fait de
façon générique :

map[ <Robot, Object> ] = collide( Robot&, Object& );

Cette exemple est du n'importe quoi, mais c'est pour l'exemple.

Le problème c'est que la paire <Robot, Object> ne peut pas exister,
puisque Object n'est jamais instancié...

Vous avez une méthode pour assouplir ça ?

Et il faudrait aussi que la map ne soit pas 'triée' puisqu'il faut que
<Robot, Robot> 'match' avant <Robot, Object>.



--------------------------------------------
Benoît Rousseau : roussebe at spray dot se
Jouez en programmant : http://realtimebattle.sourceforge.net/

2 réponses

Avatar
Ivan Vecerina
Bonjour,
"Benoit Rousseau" wrote in message
news:3fc245c8$0$28302$
Pour programmer la collision entre 2 objects d'une arène, je comptais
utiliser un dispatcher. Scott Meyer décrit (je n'ai pas le livre donc je
fausse peut être ses propos) un dispatcher utilisant un map et une pair
de typeinfo comme clef.
...

Vous avez une méthode pour assouplir ça ?

Et il faudrait aussi que la map ne soit pas 'triée' puisqu'il faut que
<Robot, Robot> 'match' avant <Robot, Object>.


Une autre référence clef pour les multiméthodes est Andrei Alexandrescu
(chap. 11 de Modern C++ Design, voir www.moderncppdesign.com).
C'est complexe, mais je pense que l'ordre d'évaluation correct
sera respecté.
Voir aussi la librairie Loki issue du livre, disponible en tant que
projet sur sourceforge: http://sourceforge.net/projects/loki-lib/
Fichier spécifique: http://minilien.com/?NaTYAcLPx0

Ceci dit, si le nombre de cas est réduit, une implémentation
manuelle avec qq dynamic_cast-s, initialement, pourrait être
une solution à envisager...


Salutations,
Ivan
--
http://ivan.vecerina.com

Avatar
kanze
Benoit Rousseau wrote in message
news:<3fc245c8$0$28302$...

Pour programmer la collision entre 2 objects d'une arène, je comptais
utiliser un dispatcher. Scott Meyer décrit (je n'ai pas le livre donc
je fausse peut être ses propos) un dispatcher utilisant un map et une
pair de typeinfo comme clef.

Je trouve cette méthode très souple, mais pas assez. En effet, la
collision d'un robot avec un autre robot est la seule nécessitant de
connaitre le type des deux objects :

map[ <Robot, Robot> ] = collide( Robot&, Robot& );

et une colision entre robot et un autre objet dans l'arene se fait de
façon générique :

map[ <Robot, Object> ] = collide( Robot&, Object& );

Cette exemple est du n'importe quoi, mais c'est pour l'exemple.

Le problème c'est que la paire <Robot, Object> ne peut pas exister,
puisque Object n'est jamais instancié...

Vous avez une méthode pour assouplir ça ?

Et il faudrait aussi que la map ne soit pas 'triée' puisqu'il faut que
<Robot, Robot> 'match' avant <Robot, Object>.


Tu as combient de types d'objets ? Dans la passée, il m'est arrivé à
utiliser une simple recherche linéaire pour de tels problèmes. Du coup,
je définis mes propres critéres pour « trouvé », et puisque j'effectue
la recherche dans l'ordre, je peux bien m'organiser pour avoir un
traitement par défaut (qui passe toujours) à la fin.

La seule particularité ici, c'est comment déterminer si une entrée passe
ou non. J'imaginerais quelque chose du genre :

struct AbstractAcceptor
{
virtual ~AbstractAcceptor() {}
bool matches( Object const* obj1 ) const = 0 ;
} ;

template< typename T >
struct Acceptor : public AbstractAcceptor
{
bool matches( Object const* obj ) const
{
return dynamic_cast< T const* >( obj ) != NULL ;
}
} ;

Dans ton cas, je crois que j'aurais tendance à organiser la table en
deux dimensions : std::vector< AbstractAcceptor const*, std::vector<
AbstractAcceptor const*, CollisionHandler* >* >. La recherche dans les deux
cas s'effectue avec quelque chose du genre :

template< typename MapType >
class Matcher
{
public:
Matcher( Object const* obj ) : myObj( obj ) {}
bool operator()( MapType::value_type const& elem ) const
{
return elem->first->matches( myObj ) ;
}
private:
Object const* myObj ;
} ;

et std::find_if. (Je m'arrangerais aussi pour que la dernière entrée de
toutes les tables a comme clé Acceptor< Object >. Comme ça, c'est
garantit que std::find_if trouve quelque chose.)

Pour ton cas particulier, il faudrait donc initialiser avec :

// On définit notre propre pair, de façon à pouvoir
// utiliser l'initialisation statique...
template< typename T >
struct TypePair
{
AbstractAcceptor const* first ;
T second ;
} ;
Acceptor< Robot > const robotAcceptor ;
Acceptor< Object > const universalAcceptor ;
TypePair< CollisionHandler* >
robotCollisionMap[] {
{ &robotAcceptor , &robotRobotCollisionHandler },
{ &universalAcceptor , &defaultCollisionHandler },
} ;
TypePair< CollisionHandler* >
defaultCollisionMap[] {
{ &universalAcceptor , &defaultCollisionHandler },
} ;
TypePair< TypePair< CollisionHandler* > >
collisionMap[] {
{ &robotAcceptor , robotCollisionMap },
{ &universalAcceptor , defaultCollisionMap },
} ;

Et l'appel :

(*std::find_if(
std::find_if(
collisionMap,
NULL,
Matcher< TypePair< TypePair< CollisionHandler* > >( obj1 )
)->second,
NULL,
Matcher< TypePair< CollisionHandler* >( obj2 ) )->second)
( obj1, obj2 ) ;

À vrai dire, je ne suis pas sûr que la déduction des types marche dans
ce cas-ci, avec les NULL. Il faudrait probablement passer la bonne
deuxième adresse. Ce qui veut dire l'introduction des temporaires, parce
qu'on ne peut pas enchaîner les appels à cause de l'idiome du double
itérateur.

Note qu'ici, je me suis basé sur le principe qu'on s'assure
systèmatiquement que la dernière entrée dans tous les tables a
l'universalAcceptor comme clé. Sinon, il faudrait bien prévoyer le cas
où la recherche échoue. Ce qui complique la vie pas mal.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16