OVH Cloud OVH Cloud

Genre de IEnumerable en C++ ?

15 réponses
Avatar
Mic Mon
Bonjour,

J'aimerais mettre en place une interface =E0-la IEnumerable<T>. En 2
mots, c'est une classe C# de base pour toutes les collections
enumerables, qui permet de traiter de fa=E7on uniforme list et vector
par exemple, lorsqu'on a des boucles du types "foreach ()".

J'aimerais faire la m=EAme chose, ie. j'ai une interface "Interface" que
j'aimerais voir avec 2 m=E9thodes abstraites : "AddChild (Children*)" et
"getChildren (Children*)". Mais que donner comme type de retour =E0
"getChildren" ?

Le probl=E8me est que j'aimerais que les utilisateurs de l'interface ne
voient pas si c'est une std::list ou std::vector ou autre, qu'ils
aient juste le moyen de faire quelque chose du type for_each dedans
(genre BOOST_FOREACH).

Vu que c'est une m=E9thode virtuelle =E0 impl=E9menter dans les classes
d'impl=E9mentation, je ne peux pas en faire une m=E9thode avec template,
donc les solutions =E0 base de "renvoyer une paire d'iterator begin/end"
ou du boost:range me semblent =E9chouer (oblig=E9 de dire si l'iterator
vient de list ou vector ou autre).

Il y aurait la possibilit=E9 de passer en param=E8tre template =E0 cette
interface le container utilis=E9, mais =E7a a le side effect de changer le
type, donc je ne pourrai pas stocker des impl=E9mentations avec
diff=E9rents containers dans un m=EAme vector par exemple. En plus =E7a
couple trop.

La seule chose que je vois est de faire un Adaptor pour iterator,
genre IIterator<T> qui forwarde les appels, puis de tout faire passer
par =E7a (ie. retourner un tel objet/range).

Vu que =E7a demande pas mal d'efforts, je voulais vous demander si vous
n'avez pas une meilleure id=E9e. Ou alors mon id=E9e de d=E9part n'est pas
un bon design ?

Merci,

Michael, qui revient quelques ann=E9es plus tard :)

5 réponses

1 2
Avatar
Mic Mon
On 23 jan, 02:02, Fabien LE LEZ wrote:
On Fri, 22 Jan 2010 16:12:27 -0800 (PST), Mic Mon
:
Tu essaies d'implémenter un truc assez compliqué, pour pouvoir
accomoder une fonctionnalité dont tu n'es pas sûr d'avoir besoin.
C'est donc un cas typique de généralisation abusive.



Oui en fait c'est aussi ce que dit Meyers dans Effective STL, il
recommande ne pas essayer de généraliser sur les conteneurs.

Mais je trouve étonnant que le type sous-jacent soit toujours obligé
d'être visible.

Utilise plutôt des typedef pour pouvoir changer le conteneur
facilement en cas de besoin. Et en attendant, tu peux suivre une des
règles de base : utilise std::vector<> tant que tu n'as pas de bonne
raison d'utiliser autre chose. Et attends pour en changer que ton
profiler t'indique un coût important de vector<>::insert().



Ok, c'est ce que je vais faire merci.

Mic
Avatar
Mic Mon
On 23 jan, 03:28, Fabien LE LEZ wrote:
On Fri, 22 Jan 2010 16:31:03 -0800 (PST), Mic Mon
:
>    return make_pair ( make_iterator (mon_conteneur_connu.begin(),
>mon_conteneur_connu.end()));

N'insère pas de retours à la ligne au milieu de tes lignes de code,
c'est très difficile à lire !



En fait je poste depuis groups.google.fr parce que je change tout le
temps de connexion en ce moment, c'est lui qui a mis le newline :(

make_iterator (...) renvoie un objet de quel type ?
make_pair (...) renvoie un objet de quel type ?
Le type renvoyé est-il bien convertible en un
"boost::range<IIterator<MonTypeConnu>, IIterator<MonTypeConnu> >" ?

D'ailleurs, peut-on construire un objet de type
"boost::range<IITerator<Type>, IIterator<Type> >", sachant que
IIterator<Type> est une classe abstraite ?



Oui j'ai écrit trop vite. En fait je voulais dire
boost:range<shared_ptr<IIterator<Type>>> en ajustant les 2 ou 3 lignes
de mon code comme il faut, désolé. Mais ça commence à faire beaucou p
d'indirections tout ça (ceci dit ça marcherait il me semble).

En particulier, std::make_pair<> effectue une copie de ses arguments.
Du coup, il transforme deux Iterator<> en un
pair<Iterator<>,Iterator<>>.
Il ne peut pas fonctionner avec des IIterator car cette classe est
abstraite : on ne peut pas en créer d'instances.



Oui en fait dans la version non fausse de ce que je voulais dire,
c'est boost::make_iterator_range mais c'est pareil.

Mic
Avatar
Mic Mon
On 23 jan, 07:55, ld wrote:
> J'aimerais mettre en place une interface à-la IEnumerable<T>. En 2
> mots, c'est une classe C# de base pour toutes les collections
> enumerables, qui permet de traiter de façon uniforme list et vector
> par exemple, lorsqu'on a des boucles du types "foreach ()".

quelle est le probleme avec la STL ?



J'aurais aimé ne pas montrer à l'extérieur quel conteneur STL est
utilisé par la collection. Or le type d'iterator en dépend, et il
semble que du coup on est obligé de rendre l'information publique (et
fixée) par un typedef. Sinon il faudrait abstraire le type d'iterator
comme dans une branche du thread, mais c'est trop lourd.

Je pense qu'il faut bien definir ton probleme et distinguer deux cas.
Soit le conteneur est connu a la compilation et dans ce cas la STL
devrait satisfaire la pluspart des besoins (cf liens ci-dessus). Soit
le conteneur n'est pas connu a la compilation et dans ce cas il y a
beaucoup a faire/ecrire pour arriver au meme niveau que la STL et
mieux vaut chercher une bibliotheque qui fait deja cela.



Oui voilà, on pourrait dire que le conteneur n'est pas connu à la
compil vu qu'il dépendrait de l'implémentation de l'interface.

Sinon ce n'est pas forcement le bon langage car l'utiliser dans de tel
cas reviendrait a ecrire un "interpreteur". Ce n'est biensur pas
impossible, mais cela veut dire ecrire une sorte de framework a-la-STL
en tout dynamique que l'on appelle un "Adaptive Object Model". Mais si
tel est ton besoin, peut-etre considerer un langage plus dynamique
permettra de resoudre le probleme plus efficacement.



Ah ok ça a un nom. Je vais regarder, merci.

> Vu que ça demande pas mal d'efforts, je voulais vous demander si vous
> n'avez pas une meilleure idée. Ou alors mon idée de départ n'est pas
> un bon design ?

Peut-etre regarder du cote de Boost, Qt, Poco, Root pour voir ce qui a
deja ete fait serait un gain de temps? Une alternative rapide
consisterait a utiliser la STL (ou boost) avec boost::variant ou
boost::any suivant les besoins.



Merci pour les pointeurs !

Mic
Avatar
Mic Mon
On 23 jan, 11:45, FX wrote:
>>    return make_pair ( make_iterator (mon_conteneur_connu.begin(),
>> mon_conteneur_connu.end()));

Comme Fabien, je ne comprends pas ce qu'est cette fonction make_pair à
un seul argument.



Oui zut, je voulais juste dire "faire un range avec begin et end".
J'avais commencé avec une paire et pis plouf.

 >> boost::range<IIterator<MonTypeConnu>, IIterator<MonTypeConnu> >
 >> InterfaceConcrete::getChildren ()

Je ne comprends pas non plus l'intérêt d'utiliser boost::range. Mais je
ne connais pas bien cette librairie.



Je l'utilise parce que ça dit exactement le sens de l'objet retourné à
l'appelant, c'est déjà implémenté et robuste, et ça permet le
BOOST_FOREACH par exemple qui est bien pratique.

Mic
Avatar
Fabien LE LEZ
On Sun, 24 Jan 2010 01:16:33 -0800 (PST), Mic Mon
:

Mais je trouve étonnant que le type sous-jacent soit toujours obligé
d'être visible.



C'est le principe du modèle C++ : écrire
MaClasse objet;
c'est allouer un objet de type "MaClasse" sur la pile, ce qui ne peut
se faire que si le compilo peut calculer sizeof(MaClasse).
Du coup, tous les membres doivent être visibles (même les membres
privés).

Certes, on peut le contourner (via l'idiome pimpl par exemple), mais
ce n'est que ça : un contournement.
1 2