 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Amerio Guest
|
Posted: Fri Apr 02, 2004 12:34 pm Post subject: [code] [solution] Re: grouper selon le type ? |
|
|
Amerio wrote:
| Quote: | Bonjour,
Considerons l'arborescence d'heritage suivante :
Base
+-----Derive1
+--------Derive1Plus
+-----Derive2
+--------Derive2Plus
J'ai une centaine d'objet, selon ce diagramme d'heritage, et je fais tres
souvent des recherches selon le type.
Actuellement, tous mes objets (300) sont dans un seul conteneur
(vector<Base*>), et je dois faire des dynamic_cast ou des typeid pour
verifier si l'objet sur lequel j'itere correspond a ce que je veux. Et
c'est
assez penalisant aux niveaux des perf (c'est pour un jeu sur console).
Je cherche donc a regrouper dans des conteneurs spécialisés ces objets
selon
leur type.
|
Je poste ici la solution a laquelle je suis arrivé (Merci Hylvenir pour
l'idée du multimap)
L'avantage est que le conteneur (world) n'as pas besoin du tout de connaitre
l'arborescence d'heritage. Et le code est typesafe (le seul dynamic_cast est
sur, car on relie avec le meme type que ce avec quoi on a stocké).
(Au passage, le dynamic_cast pourrait surement etre remplacé par un
static_cast)
@@@@@@@@@@@@@@@@@@@@@@@@@
base.h :
#include <string>
class Base
{
public:
Base(std::string const& n):name(n) {}
virtual ~Base() {}
public:
std::string name;
};
class Derived : public Base
{
public:
Derived(std::string const& n):Base(n) {}
};
class DerivedMore : public Derived
{
public:
DerivedMore(std::string const& n):Derived(n) {}
};
@@@@@@@@@@@@@@@@@@@@@@@@@
world.h
#include <map>
#include <string>
#include <iostream>
#include "base.h"
class world
{
public:
world() {}
~world() {}
/// Etat
bool empty() const { return m_mmap_idbase.empty(); }
/// Effacement
void clear() { m_mmap_idbase.clear(); }
/// Ajout d'un element
void insert(Base* b);
/// Type du conteneur multimap contenant les elements
typedef std::multimap<std::string, Base*> mmap;
/// Classes d'iterateurs sur le conteneur [template]
template <class T> struct iterator;
template <class T> struct const_iterator;
/// Iterateurs de debut [template]
template<class T> inline iterator<T> begin();
template<class T> inline const_iterator<T> begin() const;
/// Iterateurs de fin
inline mmap::iterator end();
inline mmap::const_iterator end() const;
/// Macros d'iteration sur les elements selon le type
#define foreach(iter_, world_, type_)
for(world::iterator<type_>
iter_ = world_.begin<type_>();
iter_!= world_.end();
++iter_)
#define foreach_const(iter_, world_, type_)
for(world::const_iterator<type_>
iter_ = world_.begin<type_>();
iter_!= world_.end();
++iter_)
/// Iterateur sur element [template]
template <class T>
struct iterator
{
iterator(mmap::iterator i) :iter( i ) {}
T operator *() { return *static_cast<T*>( (*iter).second ); }
void operator++() { ++iter; }
void operator--() { --iter; }
bool operator!=(iterator const& i) const { return iter!=i.iter;}
bool operator==(iterator const& i) const { return iter==i.iter;}
bool operator!=(mmap::iterator const& i) const { return iter!=i;}
bool operator==(mmap::iterator const& i) const { return iter==i;}
mmap::iterator iter;
};
/// Iterateur sur element constant [template]
template <class T>
struct const_iterator
{
const_iterator(iterator<T> i) :iter( i.iter ) {}
const_iterator(mmap::iterator i) :iter( i ) {}
const_iterator(mmap::const_iterator i) :iter( i ) {}
T const operator *() { return *static_cast<T const*>( (*iter).second ); }
void operator++() { ++iter; }
void operator--() { --iter; }
bool operator!=(const_iterator const& i) const { return iter!=i.iter;}
bool operator==(const_iterator const& i) const { return iter==i.iter;}
bool operator!=(mmap::const_iterator const& i) const { return iter!=i;}
bool operator==(mmap::const_iterator const& i) const { return iter==i;}
mmap::const_iterator iter;
};
protected:
mmap m_mmap_idbase;
};
// Inlines
template<class T>
inline world::iterator<T> world::begin()
{
return iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
template<class T>
inline world::const_iterator<T> world::begin() const
{
return const_iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
inline world::mmap::iterator world::end()
{
return m_mmap_idbase.end();
}
inline world::mmap::const_iterator world::end() const
{
return m_mmap_idbase.end();
}
inline void world::insert(Base* b)
{
std::cout << "INSERT -> "
<< b->name << " : "
<< typeid(*b).name()
<< std::endl;
// Insertion de l'objet b
m_mmap_idbase.insert( std::make_pair( typeid(*b).name(), b) );
}
@@@@@@@@@@@@@@@@@@@@@@@@@
programme de test :
#include
#include "world.h"
#include "base.h"
int main(int argc, char* argv[])
{
world w;
DerivedMore m1("m1"), m2("m2");
Base b("b");
Derived d1("d1"), d2("d2");
Base *pb = &d1;
w.insert( &m1 );
w.insert( pb );
w.insert( &m2 );
w.insert( &b );
w.insert( &d2 );
std::cout << "nDerivedMore :" << std::endl;
foreach_const( i, w, DerivedMore )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nDerived :" << std::endl;
foreach_const( i, w, Derived )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nBase :" << std::endl;
foreach_const( i, w, Base )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@
sortie :
INSERT -> m1 : class DerivedMore
INSERT -> d1 : class Derived
INSERT -> m2 : class DerivedMore
INSERT -> b : class Base
INSERT -> d2 : class Derived
DerivedMore :
m1 class DerivedMore
m2 class DerivedMore
Derived :
d1 class Derived
d2 class Derived
m1 class Derived
m2 class Derived
Base :
b class Base
d1 class Base
d2 class Base
m1 class Base
m2 class Base
|
|
| Back to top |
|
 |
Franck Branjonneau Guest
|
Posted: Fri Apr 02, 2004 9:11 pm Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
"Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
| Quote: | Amerio wrote:
Je cherche donc a regrouper dans des conteneurs spécialisés ces objets
selon
leur type.
|
*Des* conteneurs.
| Quote: | Je poste ici la solution a laquelle je suis arrivé (Merci Hylvenir pour
l'idée du multimap)
|
*Un* conteneur.
J'évais cru comprendre que tu voulais séparer tes instances en
fonction de leur type statique -- et ce pour des raisons de
performance. La solution que tu présentes améliore-t-elle les
performances de ton code ?
[J'ai lu le code en diagonale.]
| Quote: | class world
{
public:
world() {}
|
Inutile.
Inutile.
| Quote: | /// Iterateurs de debut [template]
template<class T> inline iterator<T> begin();
template<class T> inline const_iterator<T> begin() const;
/// Iterateurs de fin
inline mmap::iterator end();
inline mmap::const_iterator end() const;
|
Le type de retour de end() est différent du typpe de retour de
begin() ?!?
| Quote: | /// Macros d'iteration sur les elements selon le type
|
Horrible.
| Quote: | /// Iterateur sur element [template]
template <class T
struct iterator
T operator *() { return *static_cast
|
Le type de retour n'est pas une réference ? Un static_cast ?
| Quote: | bool operator!=(const_iterator const& i) const { return iter!=i.iter;}
bool operator==(const_iterator const& i) const { return iter==i.iter;}
bool operator!=(mmap::const_iterator const& i) const { return iter!=i;}
bool operator==(mmap::const_iterator const& i) const { return iter==i;}
|
Des ambiguïtés en perspective.
| Quote: | // Inlines
template<class T
inline world::iterator
{
return iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
template<class T
inline world::const_iterator
{
return const_iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
inline world::mmap::iterator world::end()
{
return m_mmap_idbase.end();
}
inline world::mmap::const_iterator world::end() const
{
return m_mmap_idbase.end();
}
|
std::multimap<>::find(key) retourne un iterateur vers *un* élément de
clé key.
Il n'y a qu'un cas où itérer sur [begin< Type >(), end()[
n'itère que sur des élément de type Type.
Pourquoi ne pas utiliser lower/upper _bound ?
| Quote: | programme de test :
#include <iostream
#include "world.h"
#include "base.h"
int main(int argc, char* argv[])
{
world w;
DerivedMore m1("m1"), m2("m2");
Base b("b");
Derived d1("d1"), d2("d2");
Base *pb = &d1;
w.insert( &m1 );
w.insert( pb );
w.insert( &m2 );
w.insert( &b );
w.insert( &d2 );
std::cout << "nDerivedMore :" << std::endl;
foreach_const( i, w, DerivedMore )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nDerived :" << std::endl;
foreach_const( i, w, Derived )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nBase :" << std::endl;
foreach_const( i, w, Base )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
return 0;
}
|
Après avoir choisi des opérateurs d'égalité pour les itérateurs, sur
mon implémentation, ce code compile et donne :
INSERT -> m1 : 11DerivedMore
INSERT -> d1 : 7Derived
INSERT -> m2 : 11DerivedMore
INSERT -> b : 4Base
INSERT -> d2 : 7Derived
DerivedMore :
m1 11DerivedMore
m2 11DerivedMore
b 11DerivedMore
d1 11DerivedMore
d2 11DerivedMore
Derived :
d1 7Derived
d2 7Derived
Base :
b 4Base
d1 4Base
d2 4Base
--
Franck Branjonneau <fasbjx (AT) free (DOT) fr>
|
|
| Back to top |
|
 |
Hylvenir Guest
|
Posted: Fri Apr 02, 2004 10:47 pm Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Bonjour,
Je vais me mouiller un peu...
La solution avec le multimap ne devrait pas fonctionner
pour une hériarchie un peu complexe.
Voici une ébauche de solution, qui n'améliore
pas vraiment les performances mais permettent
de rendre plus lisible l'extraction d'un sous-arbre
de ton arbre d'héritage.
Ex:
A ---- AA ---- AAA
--- AAB
-- AB ---- ABA
Je vais donc garder le vector comme conteneur.
Je vais ajouter une méthode dans chacune des classes
afin déterminer la place de la classe dans la hiérarchie
classRank() qui donnera les résultats suivants:
A ---- AA ---- AAA "111"
--- AAB "112"
-- AB ---- ABA "121"
On tri le vector par un object fonction utilisant la chaine complète
représentant le rang.
Ensuite pour accèder à une sous-branche de la hiérarchie, il suffit
de récupérer par exemple tous les rangs commençant pas "11" pour
les classes issues de AA ( AA, AAA, AAB )
Voici l'idée, maintenant le brouillon de code :
// -------------------------------------
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
class A { public: virtual string classRank() const { return "1"; } };
class AA : public A
{
public:
virtual string classRank() const { return A::classRank() + "1"; }
virtual string print() const { return "AA::print()"; }
};
class AAA : public AA
{
public:
virtual string classRank() const{ return AA::classRank() + "1"; }
virtual string print() const { return "AAA::print()"; }
};
class AAB : public AA
{
public:
virtual string classRank() const { return AA::classRank() + "2"; }
virtual string print() const { return "AAB::print()"; }
};
class AB : public A
{
public:
virtual string classRank() const { return A::classRank() + "2"; }
virtual string print() const { return "AB::print()"; }
};
class ABA : public AB
{
public:
virtual string classRank() const { return AB::classRank() + "1"; }
virtual string print() const { return "ABA::print()"; }
};
// le functor de comparaison
struct compareA {
compareA( int l = 0 ) : l_( l ) {}
bool operator() ( const A* lhs, const A* rhs ) const {
if ( !l_ ) return lhs->classRank() < rhs->classRank();
return lhs->classRank().substr( 0, l_ )
< rhs->classRank().substr( 0, l_ );
}
int l_;
};
// l'insertion dans le vector trié
void inserer( vector<A*>& v, A* a )
{
v.insert( upper_bound( v.begin(), v.end(), a, compareA() ), a );
}
// la recherche avec cast, très expérimental peut être amélioré,
// mais j'ai pas trop le temps
template< typename T >
struct Recherche {
Recherche( vector<A*>& v, const A& a )
: lower_( lower_bound( v.begin(), v.end(), &a, compareA(
: a.classRank().length() ) ) ),
upper_( upper_bound( v.begin(), v.end(), &a, compareA(
a.classRank().length() ) ) )
{}
T& operator* () const { return *dynamic_cast<T*>( *lower_ ); } T*
operator-> () const { return dynamic_cast<T*>(*lower_) ; }
vector<A*>::iterator lower_, upper_;
};
int main()
{
vector< A* > vA;
vA.reserve( 120000 );
while( vA.size() < 100000 ) {
int r = rand() % 6;
switch(r){
case 0: inserer( vA, new A() ); break; case 1: inserer( vA,
new AA() ); break; case 2: inserer( vA, new AAA() ); break;
case 3: inserer( vA, new AB() ); break; case 4: inserer( vA,
new ABA() ); break; case 5: inserer( vA, new AAB() ); break;
}
}
}
// Recherche de la branche AA
Recherche< AA > v( vA, AA() );
while( v.lower_ != v.upper_ )
{
cout << '[' << (*v).classRank() << ']'
<< '[' << (*v).print() << ']';
cout << '[' << v->classRank() << ']'
<< '[' << v->print() << ']'
<< endl;
++v.lower_;
}
}
// Voilà, faut bien se mouiller en peu un jour ;-)
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Sat Apr 03, 2004 7:12 am Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Franck Branjonneau wrote:
| Quote: | "Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
Amerio wrote:
Je cherche donc a regrouper dans des conteneurs spécialisés ces objets
selon
leur type.
*Des* conteneurs.
Je poste ici la solution a laquelle je suis arrivé (Merci Hylvenir pour
l'idée du multimap)
*Un* conteneur.
J'évais cru comprendre que tu voulais séparer tes instances en
fonction de leur type statique -- et ce pour des raisons de
performance. La solution que tu présentes améliore-t-elle les
performances de ton code ?
|
J'utilise en fait dans ce cas UN multimap comme si c'etait DES conteneurs.
Je cherchais a preciser plus une fonctionnalité qu'une implémentation.
La solution que je presente m'apporte un avantage certains : la recherche
sur le type ne se fait plus que sur le 1er élément, les autres sont obtenus
par simple itération.
Dans ma solution précédente, je testais le type pour chaque élément lors du
parcours de mon conteneur.
| Quote: |
[J'ai lu le code en diagonale.]
class world
{
public:
world() {}
Inutile.
|
Pinaille... :-)
| Quote: |
~world() {}
Inutile.
|
Pinaille... :-)
| Quote: |
/// Iterateurs de debut [template]
template<class T> inline iterator<T> begin();
template<class T> inline const_iterator<T> begin() const;
/// Iterateurs de fin
inline mmap::iterator end();
inline mmap::const_iterator end() const;
Le type de retour de end() est différent du typpe de retour de
begin() ?!?
|
Il n'a pas besoin d'etre du meme type.
Mais avec t'as remarque suivante, il va devenir upper_bound() (qui lui doit
etre du meme type)
| Quote: |
/// Macros d'iteration sur les elements selon le type
Horrible.
|
Si un outil permet de rendre du code plus lisible sans effets de bords, il
ne faut pas se priver de l'outil parce que l'outil a une sale histoire. En
l'occurence, ce define prend trois arguments. Aucune chance dans _mon_ code
pour que j'ai foreach comme ca qui traine dans un autre but.
(note, celui de la stl est for_each) (pour calmer les susceptibilités, ca
peut disparaitre..)
| Quote: |
/// Iterateur sur element [template]
template <class T
struct iterator
T operator *() { return *static_cast
Le type de retour n'est pas une réference ? Un static_cast ?
|
Oops. En effet, ce devrait etre une reference, sinon c'est dangereux.
Pour le cast, comme je disais, ce devrait etre un dynamic_cast.
Mais aucun risque de pb, car je il n'y a pas d'heritages multiples (c'est
requis dans mon projet!) et le type de récuperation est le meme que le type
d'insertion (basé sur typeid().raw_name)
(oui au passage, il faut lire des raw_name et pas name partout, le name
etant juste pour etre lisible pendant mes tests)
| Quote: | bool operator!=(const_iterator const& i) const { return iter!=i.iter;}
bool operator==(const_iterator const& i) const { return iter==i.iter;}
bool operator!=(mmap::const_iterator const& i) const { return iter!=i;}
bool operator==(mmap::const_iterator const& i) const { return iter==i;}
Des ambiguïtés en perspective.
|
Les deux dernieres lignes etaient necessaires pour end(), qui n'avait pas le
meme type.
| Quote: | // Inlines
template<class T
inline world::iterator
{
return iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
template<class T
inline world::const_iterator
{
return const_iterator<T>( m_mmap_idbase.find( typeid(T).name() ) );
}
inline world::mmap::iterator world::end()
{
return m_mmap_idbase.end();
}
inline world::mmap::const_iterator world::end() const
{
return m_mmap_idbase.end();
}
std::multimap<>::find(key) retourne un iterateur vers *un* élément de
clé key.
Mon erreur vient de la doc de VCNet, qui dit : |
"Returns an iterator addressing the *first* location of an element in a
multimap that has a key equivalent to a specified key."
Pour ma justification, je n'utilisais jamais multimap avant.
| Quote: | Il n'y a qu'un cas où itérer sur [begin< Type >(), end()[
n'itère que sur des élément de type Type.
Pourquoi ne pas utiliser lower/upper _bound ?
C'est ce que je vais faire ! Merci d'avoir lever ce (gros) point noir ! |
| Quote: | programme de test :
#include <iostream
#include "world.h"
#include "base.h"
int main(int argc, char* argv[])
{
world w;
DerivedMore m1("m1"), m2("m2");
Base b("b");
Derived d1("d1"), d2("d2");
Base *pb = &d1;
w.insert( &m1 );
w.insert( pb );
w.insert( &m2 );
w.insert( &b );
w.insert( &d2 );
std::cout << "nDerivedMore :" << std::endl;
foreach_const( i, w, DerivedMore )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nDerived :" << std::endl;
foreach_const( i, w, Derived )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
std::cout << "nBase :" << std::endl;
foreach_const( i, w, Base )
{
std::cout << (*i).name << " " << typeid( *i ).name() << std::endl;
}
return 0;
}
Après avoir choisi des opérateurs d'égalité pour les itérateurs, sur
mon implémentation, ce code compile et donne :
Tu as changé le code et ca donne ca ? |
Ou bien c'est avec le code tel que je l'ai ecris ?
| Quote: | INSERT -> m1 : 11DerivedMore
INSERT -> d1 : 7Derived
INSERT -> m2 : 11DerivedMore
INSERT -> b : 4Base
INSERT -> d2 : 7Derived
DerivedMore :
m1 11DerivedMore
m2 11DerivedMore
b 11DerivedMore
d1 11DerivedMore
d2 11DerivedMore
Derived :
d1 7Derived
d2 7Derived
Base :
b 4Base
d1 4Base
d2 4Base
|
Effectivement, ca merite d'etre revu si ce n'est pas portable :-/
(la portabilité m'est indispensable !)
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Sat Apr 03, 2004 8:33 am Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Amerio a écrit :
| Quote: | [... un tas de truc ...]
|
Bouhou... Je viens de réaliser que le multimap ne marchait pas du tout en
fait, et que mon test donnait seulement l'illusion de marcher...
Avec lower_bound et upper_bound, je n'obtients plus que les elements dont le
type est *exactement* celui demandé, et non plus ceux dérivant ou etant du
type demandé (ce qui en y reflechissant bien est normal, vu le conteneur
choisi).
Bref, retour a la case départ sans toucher 20.000
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Sat Apr 03, 2004 10:03 am Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Bon, j'ai finalement trouvé une solution à mon problème
(merci Franck pour avoir relever des problemes, et Hylvenir pour les
(bonnes) idées)
Voici les modifs faites par rapport au code precedent :
class Base
{
public:
Base(std::string const& n):name(n) {make_hier();}
virtual ~Base() {}
inline std::vector<std::string> const& hier() {return m_hier;}
public:
std::string name;
protected:
std::vector<std::string> m_hier;
inline void make_hier() { m_hier.push_back(typeid(*this).name()); }
};
class Derived : public Base
{
public:
Derived(std::string const& n):Base(n) {make_hier();}
};
class DerivedMore : public Derived
{
public:
DerivedMore(std::string const& n):Derived(n) {make_hier();}
};
class Another : public Base
{
public:
Another(std::string const& n):Base(n) {make_hier();}
};
class AnotherMore : public Another
{
public:
AnotherMore(std::string const& n):Another(n) {make_hier();}
};
et pour le world :
les iterator::operator*() et const_iterator::operator*() renvoie une
references et une ref constante.
template<class T>
inline world::iterator<T> world::begin()
{
return iterator<T>( m_mmap_idbase.lower_bound( typeid(T).name() ) );
}
template<class T>
inline world::const_iterator<T> world::begin() const
{
return const_iterator<T>( m_mmap_idbase.lower_bound(
typeid(T).name() ) );
}
template<class T>
inline world::iterator<T> world::end()
{
return iterator<T>( m_mmap_idbase.upper_bound( typeid(T).name() ) );
}
template<class T>
inline world::const_iterator<T> world::end() const
{
return iterator<T>( m_mmap_idbase.upper_bound( typeid(T).name() ) );
}
inline void world::insert(Base* b)
{
std::cout << "INSERT -> "
<< b->name << " : "
<< typeid(*b).name()
<< std::endl;
// Insertion de l'objet b, selon la hierarchie d'héritage de la classe
for (std::vector
i = b->hier().begin();
i!= b->hier().end();
++i)
{
std::cout << "HIER -> "
<< (*i)
<< std::endl;
m_mmap_idbase.insert( std::make_pair( (*i), b) );
}
}
Et là, ca marche ! Youpi !
Reste plus qu'a optimiser en 'cachant' le resultat des end() pour optimiser
les boucles.
|
|
| Back to top |
|
 |
Franck Branjonneau Guest
|
Posted: Sat Apr 03, 2004 11:16 am Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
"Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
| Quote: | Franck Branjonneau wrote:
"Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
Je cherche donc a regrouper dans des conteneurs spécialisés ces objets
selon
leur type.
*Des* conteneurs.
Je poste ici la solution a laquelle je suis arrivé (Merci Hylvenir pour
l'idée du multimap)
*Un* conteneur.
J'évais cru comprendre que tu voulais séparer tes instances en
fonction de leur type statique -- et ce pour des raisons de
performance. La solution que tu présentes améliore-t-elle les
performances de ton code ?
J'utilise en fait dans ce cas UN multimap comme si c'etait DES
conteneurs. Je cherchais a preciser plus une fonctionnalité qu'une
implémentation. La solution que je presente m'apporte un avantage
certains : la recherche sur le type ne se fait plus que sur le 1er
élément, les autres sont obtenus par simple itération. Dans ma
solution précédente, je testais le type pour chaque élément lors du
parcours de mon conteneur.
|
Oui mais. Est-ce que la solution que tu présentes améliore les
performances de ton code ?
| Quote: | /// Iterateurs de debut [template]
template<class T> inline iterator<T> begin();
template<class T> inline const_iterator<T> begin() const;
/// Iterateurs de fin
inline mmap::iterator end();
inline mmap::const_iterator end() const;
Le type de retour de end() est différent du typpe de retour de
begin() ?!?
Il n'a pas besoin d'etre du meme type.
|
Tu n'utilises donc aucune fonction de la forme :
template< typename _Iterator >
void foo( _Iterator first, _Iterator last);
?
| Quote: | /// Macros d'iteration sur les elements selon le type
Horrible.
Si un outil permet de rendre du code plus lisible sans effets de
bords, il ne faut pas se priver de l'outil parce que l'outil a une
sale histoire. En l'occurence, ce define prend trois
arguments. Aucune chance dans _mon_ code pour que j'ai foreach comme
ca qui traine dans un autre but. (note, celui de la stl est
for_each) (pour calmer les susceptibilités, ca peut disparaitre..)
|
Peu m'importe que tu utilises ou non le préprocesseur ; je préfére les
fonctions templates. Mais comme tu le dis, c'est _ton_ code, et tu t'es
assuré qu'aucune des tierces parties que tu utilises n'utilse
foreach. T'es tu aussi assuré que ton ton code ne seras pas utilisé
par une tierce partie définissant foreach ?
Usuellement, les macros sont préfixées et utilisent des majuscules :
AMERIO_FOREACH.
| Quote: | (oui au passage, il faut lire des raw_name et pas name partout, le
name etant juste pour etre lisible pendant mes tests)
|
Qu'est-ce qu'un raw_name ?
| Quote: | Après avoir choisi des opérateurs d'égalité pour les itérateurs,
sur mon implémentation, ce code compile et donne :
Tu as changé le code et ca donne ca ?
Ou bien c'est avec le code tel que je l'ai ecris ?
|
C'est ton code.
--
Franck Branjonneau <fasbjx (AT) free (DOT) fr>
|
|
| Back to top |
|
 |
Franck Branjonneau Guest
|
Posted: Sat Apr 03, 2004 11:27 am Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
"Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
| Quote: | Bon, j'ai finalement trouvé une solution à mon problème
|
[...]
| Quote: | Et là, ca marche ! Youpi !
Reste plus qu'a optimiser en 'cachant' le resultat des end() pour optimiser
les boucles.
|
Ton objectif est-il toujours d'améliorer les performances ? Le cas
échéant, qu'en est-il ?
--
Franck Branjonneau <fasbjx (AT) free (DOT) fr>
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Sat Apr 03, 2004 12:10 pm Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Franck Branjonneau wrote:
| Quote: | "Amerio" <amerio (AT) hotmail (DOT) com> écrivait:
Bon, j'ai finalement trouvé une solution à mon problème
[...]
Et là, ca marche ! Youpi !
Reste plus qu'a optimiser en 'cachant' le resultat des end() pour
optimiser
les boucles.
Ton objectif est-il toujours d'améliorer les performances ? Le cas
échéant, qu'en est-il ?
|
Je n'ai pas encore fait les mesures, mais ca va venir
Pour repondre a d'autres de tes questions, ce world n'est pas censé etre un
conteneur polyvalent, comme un vector<> STL par exemple. Il sera meme
"tayloré" pour notre besoin précis.
C'est ce qui explique la macro foreach (je veux "masqué" la notion de
begin/end), car il ne doit pas y avoir d'iteration sur une partie seulement
des objets repondant a un critre, genre for_each(first_, last_), ni meme de
transform(first_, last_), etc. Le but n'est pas (du tout) de faire un
conteneur compatible STL.
Parmis les modif que je suis en train de finir : cache du calcul de end()
(je suis _sur_ qu'aucun objet ne sera ajouté dans la boucle), enlever le
vector<string> par instance (trop couteux en ram), etc.
Pour revenir au perf, l'objectif initial etait d'arriver a remplacer un
for(){ if...} par un for() tout court, et on y est . Glop glop ;-)
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Sat Apr 03, 2004 1:04 pm Post subject: Re: [code] [solution] Re: grouper selon le type ? |
|
|
Franck Branjonneau wrote:
| Quote: | Tu n'utilises donc aucune fonction de la forme :
template< typename _Iterator
void foo( _Iterator first, _Iterator last);
|
Non. Je voudrais même l'interdire.
(l'objectif n'est pas de faire un conteneur compatible STL)
| Quote: | Peu m'importe que tu utilises ou non le préprocesseur ; je préfére les
fonctions templates. Mais comme tu le dis, c'est _ton_ code, et tu t'es
assuré qu'aucune des tierces parties que tu utilises n'utilse
foreach. T'es tu aussi assuré que ton ton code ne seras pas utilisé
par une tierce partie définissant foreach ?
Usuellement, les macros sont préfixées et utilisent des majuscules :
AMERIO_FOREACH.
|
Il n'y a pas dans cette section de code tier pouvant créer des pb de
preprocesseurs.
En tout etat de cause, si l'objectif etait de faire une librairy "vendable",
écrire ces macros ne m'aurait même pas effleuré :-)
| Quote: | (oui au passage, il faut lire des raw_name et pas name partout, le
name etant juste pour etre lisible pendant mes tests)
Qu'est-ce qu'un raw_name ?
|
typeid().name() renvoie le nom non-décoré, donc lisible par un humain.
typeid().raw_name() renvoie le nom décoré, donc illisible ou presque.
name() est plus lent que raw_name() car il faut "undécoré" le nom.
raw_name() est forcement unique, pas name() (a cause des namespaces)
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|