Je suis un peu confus quant à savoir si et quand je dois utiliser typedef en C ++. Je pense que c'est un équilibre entre lisibilité et clarté.
Voici un exemple de code sans typedefs:
int sum(std::vector<int>::const_iterator first,
std::vector<int>::const_iterator last)
{
static std::map<std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator>,
int> lookup_table;
std::map<std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator>, int>::iterator lookup_it =
lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
OMI assez moche. Je vais donc ajouter quelques typedefs dans la fonction pour la rendre plus belle:
int sum(std::vector<int>::const_iterator first,
std::vector<int>::const_iterator last)
{
typedef std::tuple<std::vector<int>::const_iterator,
std::vector<int>::const_iterator> Lookup_key;
typedef std::map<Lookup_key, int> Lookup_table;
static Lookup_table lookup_table;
Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
Le code est encore un peu maladroit, mais je me débarrasse de la plupart des documents cauchemardesques. Mais il y a toujours les itérateurs vectoriels int, cette variante se débarrasse de ceux-ci:
typedef std::vector<int>::const_iterator Input_iterator;
int sum(Input_iterator first, Input_iterator last)
{
typedef std::tuple<Input_iterator, Input_iterator> Lookup_key;
typedef std::map<Lookup_key, int> Lookup_table;
static Lookup_table lookup_table;
Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);
if (lookup_it != lookup_table.end())
return lookup_it->second;
...
}
Cela semble propre, mais est-il toujours lisible?
Quand dois-je utiliser un typedef? Dès que j'ai un type de cauchemar? Dès qu'il se produit plus d'une fois? Où dois-je les mettre? Dois-je les utiliser dans les signatures de fonction ou les conserver dans l'implémentation?
c++
coding-style
futlib
la source
la source
typedef Input_iterator std::vector<int>::const_iterator;
est à l'envers#define
n'est pas assez bon.Réponses:
Votre dernier exemple est très lisible, mais cela dépend de l'endroit où vous définissez le typedef. Les typedefs de portée locale (comme dans votre deuxième exemple) sont IMVHO presque toujours une victoire.
J'aime toujours mieux votre troisième exemple, mais vous voudrez peut-être penser au nom et donner aux itérateurs des noms qui indiquent l'intention du conteneur.
Une autre option serait de créer un modèle à partir de votre fonction, afin qu'il fonctionne également avec différents conteneurs. Le long des lignes de
ce qui est également très dans l'esprit de la STL.
la source
Considérez un
typedef
comme l'équivalent de déclaration de variable d'une fonction: il est là donc vous ...Personnellement, je glaçure si je dois lire des noms de caractères longs comme à
std::vector<int>::const_iterator
plusieurs reprises.Votre troisième exemple ne se répète pas inutilement et est plus facile à lire.
la source
typedef
les déclarations ont essentiellement le même but que l'encapsulation. Pour cette raison, ils s'intègrent presque toujours mieux dans un fichier d'en-tête, en suivant les mêmes conventions de dénomination que vos classes, car:typedef
, il y a de fortes chances que les appelants le fassent aussi, surtout comme dans votre exemple où il est utilisé dans les arguments.En passant, votre code de mémorisation serait beaucoup plus propre si vous l'abrégiez davantage, comme:
la source