Quand dois-je utiliser typedef en C ++?
Question
Dans mes années de C ++ (MFC) dans la programmation que je jamais ressenti le besoin d'utiliser typedef
, donc je ne sais pas vraiment ce que ça sert. Où dois-je utiliser? Y a-t-il des situations réelles où l'utilisation est préférée de <=>? Ou est-ce vraiment plus un mot clé spécifique C?
La solution
Modèle Métaprogrammation
typedef
est nécessaires pour de nombreux - - chaque fois qu'une classe est considérée comme une « compilation fonction de type », un strip_pointer_from<double*>::type
est utilisé comme « compilation valeur de type » pour obtenir le type résultant. Par exemple. envisager simple métafonction pour convertir un type de pointeur à son type de base:
template<typename T>
struct strip_pointer_from;
template<typename T>
struct strip_pointer_from<T*> { // Partial specialisation for pointer types
typedef T type;
};
Exemple: l'expression de type double
évalue à <=>. Notez que métaprogrammation modèle n'est pas couramment utilisé en dehors du développement des bibliothèques.
Types de pointeur Simplifier Fonction
<=> est utile pour donner un court alias pointu pour les types de pointeur de fonction complexe:
typedef int (*my_callback_function_type)(int, double, std::string);
void RegisterCallback(my_callback_function_type fn) {
...
}
Autres conseils
Dans le livre de Bjarne il indique que vous pouvez utiliser typedef pour faire face aux problèmes de portabilité entre les systèmes qui ont des tailles entières. (Version paraphraser)
Sur une machine où est 4 vous sizeof(int)
pouvez
typedef int int32;
Ensuite, utilisez partout dans votre int32
code. Lorsque vous passez à une implémentation de C ++ où est 2 typdef
, alors vous pouvez simplement changer le <=>
typedef long int32;
et votre programme continuera à fonctionner sur la nouvelle mise en œuvre.
utilisation avec pointeur de fonction
Masquer la fonction pointeur Déclarations avec un typedef
void (*p[10]) (void (*)() );
Seuls quelques programmeurs peuvent dire que p est un « tableau de 10 pointeurs à une fonction de retour vide et en prenant un pointeur vers une autre fonction qui renvoie vide et ne prend aucun argument. » La syntaxe lourde est presque indéchiffrable. Cependant, vous pouvez simplifier considérablement en utilisant typedef déclarations. Tout d'abord, déclarer un typedef pour « pointeur vers une fonction renvoyant vide et sans argument » comme suit:
typedef void (*pfv)();
Ensuite, déclare un autre typedef pour « pointeur vers une fonction qui retourne vide et prendre une VFP » sur la base typedef nous avons précédemment déclaré:
typedef void (*pf_taking_pfv) (pfv);
Maintenant que nous avons créé le typedef pf_taking_pfv comme synonyme de la trop compliqué « pointeur vers une fonction qui retourne vide et prendre une VFP », déclarant un tableau de 10 ces pointeurs est un jeu d'enfant:
pf_taking_pfv p[10];
Juste pour donner quelques exemples pour les choses dites: conteneurs STL
. typedef std::map<int,Froboz> tFrobozMap;
tFrobozMap frobozzes;
...
for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
{
...
}
Il est pas rare d'utiliser même typedefs comme
typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;
Un autre exemple: l'utilisation de pointeurs partagés:
class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;
[mise à jour] Comme par commentaire - où les mettre
Le dernier exemple - à l'aide shared_ptr
- est facile: sont vrai matériel d'en-tête - ou au moins un en-tête en avant. Vous avez besoin de la déclaration en avant pour shared_ptr de toute façon, et l'un de ses avantages est déclaré qu'il est sûr à utiliser avec un décl avant.
Mettez une autre façon. Si un shared_ptr vous devriez probablement utiliser le type que par une shared_ptr, séparant ainsi les déclarations ne fait pas beaucoup de sens
(. Oui, xyzfwd.h est une douleur que je les utiliser que dans les points chauds -. Sachant que les points chauds sont difficiles à identifier Blame C ++ compiler + modèle de liaison ...)
typedefs de conteneurs que j'utilise habituellement lorsque la variable conteneur est déclarée - par exemple localement pour un var local, en tant que membres de la classe lorsque l'instance de réservoir réel est un membre de la classe. Cela fonctionne bien si le type de conteneur réel est un détail de mise en œuvre -. Provoquant aucune dépendance supplémentaire
Si elles font partie d'un particulier interface, ils sont déclarés en même temps que l'interface qu'ils sont utilisés avec, par exemple.
// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes);
Cela devient problématique lorsque le type est un élément de liaison entre les différentes interfaces - à-dire du même type est nécessaire par plusieurs en-têtes. Quelques solutions:
- déclarer en même temps que le type contenu (Adapté pour les conteneurs qui sont fréquemment utilisés pour ce type)
- les déplacer vers un en-tête séparée
- passer à une tête séparée, et en faire une classe de données où le conteneur réel est un détail de mise en œuvre à nouveau
Je suis d'accord que les deux derniers ne sont pas terrible, je ne les utiliser que lorsque je reçois des ennuis (pas de manière proactive).
typedef est utile dans beaucoup de situations.
Fondamentalement, il vous permet de créer un alias pour un type. Lorsque / si vous devez changer le type, le reste du code pourrait être inchangée (cela dépend du code, bien sûr). Par exemple, disons que vous voulez iter sur un c ++ vecteur
vector<int> v;
...
for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) {
// Stuff here
}
Dans l'avenir, vous pensez peut-être changer le vecteur avec une liste, parce que le type d'opérations que vous avez à faire à ce sujet. Sans typedef vous devez changer toutes les occurrences de vecteur dans votre code. Mais si vous écrivez quelque chose comme ceci:
typedef vector<int> my_vect;
my_vect v;
...
for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) {
// Stuff here
}
Maintenant, il vous suffit de changer une ligne de code (i.e. de « typedef vector<int> my_vect
» à « typedef list<int> my_vect
») et tout fonctionne.
typedef permet aussi d'économiser du temps lorsque vous avez des structures de données complexes qui sont très longues à écrire (et difficile à lire)
Une bonne raison d'utiliser typedef est si le type de quelque chose peut changer. Par exemple, disons que pour l'instant, sont très bien pour ints 16 bits l'indexation des ensemble de données, car dans un avenir prévisible, vous aurez moins de 65535 articles et que les contraintes d'espace sont importantes ou vous avez besoin de bonnes performances de cache. Cependant, hasard que vous devez utiliser votre programme sur un ensemble de données avec plus de 65535 articles, vous voulez être en mesure de passer facilement à un nombre entier plus large. Utilisez un typedef, et il suffit de changer cela en un seul endroit.
typedef
permet non seulement d'avoir un alias pour les types complexes, mais vous donne un endroit naturel pour documenter un type. Je l'utilise parfois pour des fins de documentation.
Il y a aussi des moments où j'utilise un tableau d'octets. Maintenant, un tableau d'octets pourrait signifier beaucoup de choses. Rend pratique <=> pour définir mon tableau d'octets comme « hash32 » ou « ContenuFichier » pour rendre mon code plus lisible.
monde réel utilise des typedef:
- fournir des alias pour les types sympathiques templated prolixes
- fournir des alias conviviaux pour les types de pointeur de fonction
-
fournir des étiquettes locales pour les types, par exemple:.
template<class _T> class A { typedef _T T; }; template<class _T> class B { void doStuff( _T::T _value ); };
Il y a un autre cas d'utilisation à utiliser typedef est quand nous voulons permettre une sorte de Container Code indépendant (mais pas exactement!)
Disons que vous avez la classe:
Class CustomerList{
public:
//some function
private:
typedef list<Customer> CustomerContainer;
typedef CustomerContainer::iterator Cciterator;
};
Le code ci-dessus encapsule la mise en œuvre du conteneur interne en utilisant typedef et même si à l'avenir les besoins de conteneurs de liste changé au vecteur ou deque encore l'utilisateur de la classe ListeClient n'a pas à se soucier de la mise en œuvre du conteneur exact.
Par conséquent, le typedef encapsule et nous aider un peu à écrire du code Independent Container
Chaque fois qu'il rend plus clair ou mieux de lire la source.
J'utilise genre de typedef en C # pour les génériques / modèles. Un « NodeMapping » est juste préférable de lire / utiliser et comprendre alors beaucoup de « Dictionnaire
Typedef permet une certaine flexibilité dans votre classe. Lorsque vous voulez changer le type de données dans le programme, vous n'avez pas besoin de changer plusieurs endroits, mais juste besoin de changer une occurrence.
typedef <datatype example int or double> value_type
vous pouvez donner le nom même au lieu de value_type
, mais est normalement le <=> nom standard.
u peut utiliser typedef comme
value_type i=0; //same as a int or double i=0;
... et vous n'avez pas besoin d'un Typedef pour un ou ENUM struct.
Ou avez-vous?
typedef enum { c1, c2 } tMyEnum;
typedef struct { int i; double d; } tMyStruct;
peut être mieux écrit
enum tMyEnum { c1, c2 }
struct tMyStruct { int i; double d; };
Est-ce exact? Qu'en est-C?