2008-09-24 6 views
1

Un modèle commun avec des conteneurs STL est la suivante:STL comme conteneur typedef raccourci?

map<Key, Value> map; 
for(map<Key, Value>::iterator iter = map.begin(); iter != map.end(); ++iter) 
{ 
    ... 
} 

Ainsi, afin d'éviter d'écrire la déclaration des paramètres du modèle, nous pouvons le faire quelque part:

typedef map<Key, Value> TNiceNameForAMap; 

Mais si cette carte est utilisée uniquement dans une seule fonction ou pour une seule itération, c'est un surcoût ennuyeux.

Y a-t-il un moyen de contourner ce typedef?

Répondre

10

Vous ne savez pas exactement ce que vous entendez par "frais généraux". Si cela simplifie la façon dont vous écrivez votre code, utilisez-le, sinon tenez-vous en à la main.

S'il n'est utilisé que dans une portée restreinte, placez typedef dans la même portée. Ensuite, il n'a pas besoin d'être publié, ou documenté, ou apparaître sur les diagrammes UML. Par exemple (et je ne prétends pas que ce soit le meilleur code jamais à d'autres égards):

int totalSize() { 
    typedef std::map<Key, Value> DeDuplicator; 
    DeDuplicator everything; 

    // Run around the universe finding everything. If we encounter a key 
    // more than once it's only added once. 

    // now compute the total 
    int total = 0; 
    for(DeDuplicator::iterator i = everything.begin(); i <= everything.end(); ++i) { 
     total += i->second.size(); // yeah, yeah, overflow. Whatever. 
    } 
    return total; 
} 

La combinaison avec la suggestion de Ferruccio (si vous utilisez boost), la boucle devient:

BOOST_FOREACH(DeDuplicator::pair p, everything) { 
    total += p.second.size(); 
} 

Et en combinant avec la suggestion de bk1e (si vous utilisez C++ 0x ou avec des fonctionnalités de celui-ci), et en supposant que BOOST_FOREACH interagit avec auto de la manière dont je pense qu'il devrait basé sur le fait qu'il peut normalement gérer les conversions implicites types:

std::map<Key, Value> everything; 
// snipped code to run around... 
int total = 0; 
BOOST_FOREACH(auto p, everything) { 
    total += p.second.size(); 
} 

Pas mal.

+1

Bien joué! Votre dernier est au niveau de Python en compacité * et * lisibilité. – rlerallut

+0

Et pourrait même courir plus vite. –

5

Vous pouvez utiliser Boost.Foreach

+0

Bon appel, puisque la verbosité de la boucle est plus grande que la verbosité typedef de toute façon ... –

+1

Oui, et la meilleure partie est la syntaxe est assez similaire à une construction C++ 0x foreach que vous devriez être en mesure de mettre à jour votre code avec un regex recherche et remplace quand votre compilateur prend en charge cela. – Ferruccio

2

Personnellement, je pense MyMap :: iterator est plus lisible que carte < int, string > :: iterator ou même std :: carte < int, std :: string > :: itérateur donc je fais toujours le typedef. Le seul surcoût est une ligne de code. Une fois le code compilé, il n'y aura pas de différence de taille ou de vitesse de l'exécutable. C'est juste une question de lisibilité.

3

Une future version de la norme C++ (connu sous le nom C++0x) présentera un new use for the auto keyword, vous permettant d'écrire quelque chose comme ce qui suit:

map<Key, Value> map; 
for(auto iter = map.begin(); iter != map.end(); ++iter) 
{ 
    ... 
} 
+0

Woohoo! Taper fort comme si ça devait être. –

0

Si l'typedef est locale à une seule fonction, il ne même besoin d'être un joli nom. Utilisez X ou MAP, comme dans un modèle.

+0

Les variables n'ont pas besoin d'avoir de beaux noms non plus. Mais c'est bien s'ils le font ;-) –

0

C++ 0x offrira également une boucle à base de distance, ce qui est similaire à itératif pour la boucle dans d'autres langages.

Malheureusement, GCC n'implémente pas encore la plage de valeurs pour (mais implémentent automatiquement).

Editer: En attendant, pensez aussi à typer l'itérateur.Il ne contourne pas le typedef à usage unique (sauf si vous mettez cela dans un en-tête, ce qui est toujours une option), mais il raccourcit le code résultant de one :: iterator.

0

Au cours des dernières années, j'ai vraiment essayé de ne plus utiliser de boucles écrites manuellement plutôt que d'utiliser les algorithmes STL. Votre code ci-dessus peut être modifié à:

struct DoLoopBody { 
    template <typename ValueType> 
    inline void operator()(ValueType v) const { 
    // ... 
    } 
}; 

std::for_each (map.begin(), map.end(), DoLoopBody()); 

Malheureusement, la DoLoopBody de classe ne peut pas être une classe locale, qui est souvent citée comme un inconvénient. Cependant, je vois cela comme un avantage en ce que le corps de la boucle peut maintenant être testé unitairement de manière isolée.

+0

Le problème avec ça (et je ne blâme pas votre utilisation, je blâme STL) c'est que ce n'est pas vraiment une boucle foreach, parce que vous spécifiez le début et la fin conditions. C'est plus comme l'opérateur de la gamme Perl. –

+0

Notez également que le futur standard C++ 0x inclura quelque chose qui ressemble à des fonctions lambda, ce qui rendra le code plus compact (pas plus facile à lire, cependant, à mon humble avis). Bon point sur le test du corps de la boucle en isolation. – rlerallut

Questions connexes