Quelque chose que je me suis souvent trouvé à faire dernièrement consiste à déclarer des modifications de type relatives à une classe particulière à l'intérieur de cette classe, c'est-à-dire.
class Lorem
{
typedef boost::shared_ptr<Lorem> ptr;
typedef std::vector<Lorem::ptr> vector;
//
// ...
//
};
Ces types sont ensuite utilisés ailleurs dans le code:
Lorem::vector lorems;
Lorem::ptr lorem( new Lorem() );
lorems.Push_back( lorem );
Les raisons qui me plaisent:
std::vector<Lorem>
devient Lorem::vector
, etc.boost::shared_ptr
et stocké dans un vecteur.boost::intrusive_ptr
) à un stade ultérieur, cela aurait un impact minimal sur le code.Raisons pour lesquelles je n'aime pas ça:
Lorem::vector
au sein d’une autre classe mais n’a besoin (ou ne souhaite) que de transmettre la déclaration de Lorem (par opposition à l’introduction d’une dépendance sur son fichier d’en-tête), vous devrez alors utiliser les types explicites (par exemple, boost::shared_ptr<Lorem>
plutôt que Lorem::ptr
), ce qui est un peu incohérent.J'essaie d'être objectif avec mon style de codage, il serait donc bon d'obtenir d'autres opinions sur celui-ci afin de pouvoir disséquer un peu ma pensée.
Je pense que c'est un excellent style, et je l'utilise moi-même. Il est toujours préférable de limiter autant que possible la portée des noms, et l'utilisation de classes est le meilleur moyen de le faire en C++. Par exemple, la bibliothèque standard C++ utilise beaucoup de ressources typées au sein des classes.
Cela sert de déclaration d'intention - dans l'exemple ci-dessus, la classe Lorem est destinée à être comptée de référence via boost :: shared_ptr et stockée dans un vecteur.
C'est exactement ce que ça fait pas faire.
Si je vois "Foo :: Ptr" dans le code, je ne sais absolument pas si c'est un shared_ptr ou un Foo * (STL a :: pointer typedefs qui sont T *, rappelez-vous) ou peu importe. Esp. S'il s'agit d'un pointeur partagé, je ne fournis pas du tout de texte, mais conserve l'utilisation explicitée de shared_ptr dans le code.
En fait, je n’utilise presque jamais de types de caractères en dehors de la métaprogrammation des modèles.
La STL fait ce genre de chose tout le temps
La conception STL avec des concepts définis en termes de fonctions membres et de typedefs imbriquées est un cul-de-sac historique, les bibliothèques de modèles modernes utilisent des fonctions libres et des classes de traits (cf. Boost.Graph), car elles n'excluent pas les types intégrés. modéliser le concept et parce qu'il facilite l'adaptation de types qui n'ont pas été conçus avec les concepts des bibliothèques de modèles donnés.
N'utilisez pas le TSL comme une raison pour faire les mêmes erreurs.
Les typedefs sont ceux que conception et traits basés sur des règles construits en C++, la puissance de la programmation générique en C++ provient donc des typedefs eux-mêmes.
Les typdefs sont vraiment bon style. Et toutes vos "raisons que j'aime" sont bonnes et correctes.
Des problèmes que tu as avec ça. Eh bien, la déclaration anticipée n’est pas un saint graal. Vous pouvez simplement concevoir votre code pour éviter les dépendances à plusieurs niveaux.
Vous pouvez déplacer typedef en dehors de la classe mais Class :: ptr est tellement plus joli que ClassPtr que je ne le fais pas. C'est comme avec les espaces de noms, comme pour moi - les choses restent connectées dans la portée.
Parfois j'ai fait
Trait<Loren>::ptr
Trait<Loren>::collection
Trait<Loren>::map
Et cela peut être par défaut pour toutes les classes de domaine et avec une spécialisation pour certaines.
Un autre vote pour que ce soit une bonne idée. J'ai commencé à faire cela en écrivant une simulation qui devait être efficace, à la fois dans le temps et dans l'espace. Tous les types de valeur avaient une typedef Ptr qui commençait par un pointeur partagé renforcé. J'ai ensuite fait du profilage et en ai transformé certains en un pointeur intrusif sans avoir à changer le code dans lequel ces objets étaient utilisés.
Notez que cela ne fonctionne que lorsque vous savez où les classes vont être utilisées et que toutes les utilisations ont les mêmes exigences. Je n'utiliserais pas cela dans le code de la bibliothèque, par exemple, car vous ne pouvez pas savoir lors de l'écriture de la bibliothèque le contexte dans lequel elle sera utilisée.
La STL fait ce genre de chose tout le temps - les typedefs font partie de l'interface de nombreuses classes de la STL.
reference
iterator
size_type
value_type
etc...
sont toutes les typedefs qui font partie de l'interface pour différentes classes de modèles STL.
Actuellement, je travaille sur du code, qui utilise intensivement ce type de typedef. Jusqu'ici, c'est bien.
Mais j’ai remarqué qu’il existe assez souvent des types de caractères itératifs, que les définitions sont réparties entre plusieurs classes et que vous ne savez jamais vraiment à quel type vous avez affaire. Ma tâche est de résumer la taille de certaines structures de données complexes cachées derrière ces typedefs - je ne peux donc pas compter sur les interfaces existantes. En combinaison avec trois à six niveaux d'espaces de noms imbriqués, cela crée de la confusion.
Donc, avant de les utiliser, il y a quelques points à considérer
Je recommande de déplacer ces types de caractères en dehors de la classe. De cette façon, vous supprimez la dépendance directe sur les classes de pointeurs et de vecteurs partagés et vous pouvez les inclure uniquement lorsque cela est nécessaire. À moins que vous n'utilisiez ces types dans votre implémentation de classe, j'estime qu'ils ne devraient pas être des typedefs internes.
Les raisons qui vous plaisent sont toujours les mêmes, car elles sont résolues par le repliement de type via typedef, et non par leur déclaration dans votre classe.
Lorsque la typedef est utilisée uniquement dans la classe elle-même (c'est-à-dire qu'elle est déclarée privée), je pense que c'est une bonne idée. Cependant, pour les raisons que vous donnez, je ne l'emploierais pas si le typedef doit être connu en dehors de la classe. Dans ce cas, je recommande de les déplacer en dehors de la classe.