Bonjour à tous.

J'ai une question assez délicate à gérer.
Pour d'obscures raisons d'architecture tordue, j'ai plusieurs séries de choses ainsi conçues:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
typedef ... Bidule;
 
class Machin {
private:
list<Bidule> bidules;
 
public:
    list<Bidule>::const_iterator bidules_begin() const;
    list<Bidule>::const_iterator bidules_end() const;
};
 
class GrosMachin {
private:
list<Machin> machins;
 
public:
    list<Machin>::const_iterator machins_begin() const;
    list<Machin>::const_iterator machins_end() const;
};
Et bien évidemment, la majorité de mon code est de la forme:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
GrosMachin g;
for (... it_m = g.machins_begin(); it_m != g.machins_end(); ++it_m) {
   //PAS de code ici
   for (... it_b = it_m.bidules_begin(); it_b != it_m.end(); ++it_b) {
      //traiter le Bidule *it_b
   }
   //Pas de code ici non plus
}
Comme il n'y a jamais de code qui n'est pas dans la boucle interne, j'essaie d'écrire une template d'iterateur masquant la double structure.
Pour l'essentiel, je l'ai, il "suffit" d'avoir un operateur++ tel que:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
      deep_iterator & operator++() {
      unlazy();
      if (++inner_it == inner_end()) {
         ++outer_it;
         state = pending_begin;
      }
      return *this;
   }
Avec la subtilité que le state permet de ne pas stocker le outer.end() dans l'iterateur.

Logiquement, pour accéder aux bonnes fonctions begin et end, je passe par une classe de trait/police
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
template <typename T>
struct IterableTraits {
   typedef typename T::iterator iterator;
   typedef typename T::const_iterator const_iterator;
 
   static const_iterator begin(T const& t) {return t.begin();}
   static       iterator begin(T      & t) {return t.begin();}
 
   static const_iterator end(T const& t) {return t.end();}
   static       iterator end(T      & t) {return t.end();}
};
Comme ca, il suffit de la surcharger pour mon cas particulier, et tout marche tout seul.
J'envisage éventuellement d'avoir en template les pointeurs de fonctions vers begin et end, plutot que des statiques. à méditer...

Par contre, j'ai un gros soucis sur un autre point.
J'ai plusieurs cas de map<string, map<string, Truc> >, où l'on veut parcourir l'ensemble des Truc.
Et là, ca devient délicat, car ma template d'itérateur doit subitement devenir capable de discriminer les map (et multimap) des autres types, parce qu'il ne faut pas utiliser [c]*it[c] mais it->second.

La solution qui me semble la moins violente, c'est de passer par une template auxilliaire, qui ferait le bon choix. Et c'est là que je suis perdu.

A priori, la différence entre les deux genres d'accès, c'est qu'il existe un typename It::value_type::second_type.

Je tourne et retourne mon problème, sans parvenir à lui trouver une solution fonctionnelle.

J'ai essayé des choses comme:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
//SFINAE :D
template<typename It>
typename It::value_type::second_type &
iterator_value(It const& it) {return it->second;}
 
template<typename It>
typename It::reference iterator_value(It const& it) {return *it;}
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
//SFINAE deduction
template<typename It>
typename It::value_type::second_type &
iterator_value(It const& it, typename It::value_type::second_type* =0) {return it->second;}
 
template<typename It>
typename It::reference iterator_value(It const& it) {return *it;}
Mais mon cher compilateur s'entête à considérer les fonctions comme ambigües, ce qui est assez logique.

Une partie de mon problème étant que je suis coincé avec un compilateur naphtalinien (Visual 2008), qui refuse les valeurs par défaut pour les paramètres template des templates de fonction. (et aussi, refuse le C++11)
Bien évidemment, je n'ai pas non plus le droit d'utiliser boost. (je peux à la rigueur importer un petit fragment, pour peu qu'il n'y ait pas une dizaine d'autres entêtes à importer)

Quelqu'un a-t-il une idée pour écrire cette SFINAE?