¿Cuándo debería usar typedef en C ++?

En mis años de progtwigción en C ++ (MFC), nunca sentí la necesidad de usar typedef , así que no sé para qué se usa. ¿Dónde debería usarlo? ¿Hay alguna situación real donde se prefiera el uso de typedef ? ¿O es realmente más una palabra clave específica de C?

Metaprogtwigción de plantillas

typedef es necesario para muchas tareas de metaprogtwigción de plantillas : siempre que una clase se trate como una “función de tipo de tiempo de comstackción”, un typedef se utiliza como un “valor de tipo de tiempo de comstackción” para obtener el tipo resultante. Por ejemplo, considere una metafunción simple para convertir un tipo de puntero a su tipo base:

 template struct strip_pointer_from; template struct strip_pointer_from { // Partial specialisation for pointer types typedef T type; }; 

Ejemplo: la expresión de tipo strip_pointer_from::type evalúa como double . Tenga en cuenta que la metaprogtwigción de plantillas no se usa comúnmente fuera del desarrollo de la biblioteca.

Simplificando tipos de punteros de función

typedef es útil para dar un alias corto y nítido a tipos de punteros de función complicados:

 typedef int (*my_callback_function_type)(int, double, std::string); void RegisterCallback(my_callback_function_type fn) { ... } 

En el libro de Bjarne afirma que puede usar typedef para tratar los problemas de portabilidad entre sistemas que tienen diferentes tamaños enteros. (esto es una paráfrasis)

En una máquina donde sizeof (int) es 4 puedes

 typedef int int32; 

Luego usa int32 en todas partes en tu código. Cuando te mueves a una implementación de C ++ donde sizeof (int) es 2, entonces puedes simplemente cambiar el typdef

 typedef long int32; 

y su progtwig aún funcionará en la nueva implementación.

uso con puntero de función

Ocultar declaraciones de puntero de función con un typedef

 void (*p[10]) (void (*)() ); 

Solo unos pocos progtwigdores pueden decir que p es una “matriz de 10 punteros a una función que devuelve el vacío y toma un puntero a otra función que devuelve vacío y no toma argumentos”. La syntax engorrosa es casi indescifrable. Sin embargo, puede simplificarlo considerablemente mediante el uso de declaraciones typedef. En primer lugar, declare un typedef para “puntero a una función que devuelve vacío y no toma argumentos” de la siguiente manera:

  typedef void (*pfv)(); 

A continuación, declare otro typedef para “puntero a una función que devuelve vacío y tomando una pfv” en función del tipo def previamente declarado:

  typedef void (*pf_taking_pfv) (pfv); 

Ahora que hemos creado pf_taking_pfv typedef como sinónimo del “puntero a una función que devuelve vacío y toma una pfv”, declarar una matriz de 10 de estos punteros es muy fácil:

  pf_taking_pfv p[10]; 

de

Solo para dar algunos ejemplos de lo dicho: contenedores STL.

  typedef std::map tFrobozMap; tFrobozMap frobozzes; ... for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it) { ... } 

No es inusual incluso usar typedefs como

 typedef tFrobozMap::iterator tFrobozMapIter; typedef tFrobozMap::const_iterator tFrobozMapCIter; 

Otro ejemplo: usar punteros compartidos:

 class Froboz; typedef boost::shared_ptr FrobozPtr; 

[actualización] Según el comentario, ¿dónde ponerlos?

El último ejemplo, que usa shared_ptr , es fácil: es un verdadero material de encabezado, o al menos un encabezado directo. De todos modos, necesitas la statement forward para shared_ptr, y una de sus ventajas declaradas es que es seguro usarlo con un forward decl.

Dicho de otra manera: si hay un shared_ptr, probablemente deba usar el tipo solo a través de un shared_ptr, por lo que separar las declaraciones no tiene mucho sentido.

(Sí, xyzfwd.h es una molestia. Los usaría solo en zonas activas, sabiendo que los hotspots son difíciles de identificar. Culpe al modelo de comstackción + enlace de C ++ …)

Tipos de contenedordefs Usualmente uso donde se declara la variable del contenedor, por ejemplo, localmente para una var local, como miembros de la clase cuando la instancia del contenedor real es un miembro de la clase. Esto funciona bien si el tipo de contenedor real es un detalle de implementación, sin causar dependencia adicional.

Si se convierten en parte de una interfaz particular , se declaran junto con la interfaz con la que se utilizan, por ejemplo

 // FrobozMangler.h #include "Froboz.h" typedef std::map tFrobozMap; void Mangle(tFrobozMap const & frobozzes); 

Eso se vuelve problemático cuando el tipo es un elemento de enlace entre diferentes interfaces, es decir, varios encabezados necesitan el mismo tipo. Algunas soluciones:

  • declararlo junto con el tipo contenido (adecuado para contenedores que se usan con frecuencia para este tipo)
  • moverlos a un encabezado separado
  • mover a un encabezado separado y convertirlo en una clase de datos donde el contenedor real es un detalle de implementación nuevamente

Estoy de acuerdo en que los dos últimos no son tan buenos, los usaría solo cuando me meto en problemas (no de forma proactiva).

typedef es útil en muchas situaciones.

Básicamente le permite crear un alias para un tipo. Cuando / si tiene que cambiar el tipo, el rest del código no se modificará (esto depende del código, por supuesto). Por ejemplo, digamos que quieres verlo en un vector c ++

 vector v; ... for(vector::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here } 

En el futuro, puede pensar en cambiar el vector con una lista, porque el tipo de operaciones que tiene que hacer en él. Sin typedef tienes que cambiar TODAS las apariciones de vectores dentro de tu código. Pero si escribes algo como esto:

 typedef vector my_vect; my_vect v; ... for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here } 

Ahora solo tiene que cambiar una fila de código (es decir, de ” typedef vector my_vect ” a ” typedef list my_vect “) y todo funciona.

typedef también le ahorra tiempo cuando tiene estructuras de datos complejas que son muy largas para escribir (y difíciles de leer)

Una buena razón para usar typedef es si el tipo de algo puede cambiar. Por ejemplo, supongamos que, por ahora, las entradas de 16 bits están bien para indexar algunos conjuntos de datos porque en el futuro previsible, tendrá menos de 65535 elementos, y las restricciones de espacio son importantes o necesita un buen rendimiento de la memoria caché. Sin embargo, en caso de que necesite usar su progtwig en un conjunto de datos con más de 65535 elementos, desea poder cambiar fácilmente a un número entero más amplio. Use un typedef, y solo tiene que cambiar esto en un solo lugar.

typedef permite no solo tener un alias para tipos complejos, sino que también le proporciona un lugar natural para documentar un tipo. A veces lo uso con fines documentales.

También hay momentos en los que utilizo una matriz de bytes. Ahora, una matriz de bytes podría significar muchas cosas. typedef hace que sea útil definir mi matriz de bytes como “hash32”, o “fileContent” para hacer que mi código sea más legible.

Usos del mundo real de typedef:

  • proporcionando alias amistosos para tipos de plantillas prolijas
  • proporcionando alias amistosos para tipos de puntero a función
  • proporcionar tags locales para los tipos, por ejemplo:

     template class A { typedef _T T; }; template class B { void doStuff( _T::T _value ); }; 

Hay otro caso de uso para usar typedef cuando queremos habilitar un tipo de código independiente de contenedor (¡pero no exactamente!)

Digamos que tienes clase:

 Class CustomerList{ public: //some function private: typedef list CustomerContainer; typedef CustomerContainer::iterator Cciterator; }; 

El código anterior encapsula la implementación del contenedor interno usando typedef e incluso si en el futuro el contenedor de la lista necesita cambiarse a vector o deque, el usuario de la clase CustomerList no tiene que preocuparse por la implementación exacta del contenedor.

Por lo tanto, el typedef encapsula y de alguna manera nos ayuda a escribir el código Container Independent

Cada vez que hace que la fuente sea más clara o mejor para leer.

Uso tipo de typedef en C # para generics / plantillas. Un “NodeMapping” es simplemente mejor para leer / usar y comprender una gran cantidad de “Dictionary “. EN MI HUMILDE OPINIÓN. Así que lo recomendaría para plantillas.

Typedef permite flexibilidad en tu clase. Cuando desee cambiar el tipo de datos en el progtwig, no necesita cambiar varias ubicaciones, solo necesita cambiar una ocurrencia.

 typedef  value_type 

puede dar nombre a nay en lugar de value_type , pero value_type es normalmente el nombre estándar.

Entonces puedes usar typedef como

 value_type i=0; //same as a int or double i=0; 

… y usted no necesita un Typedef para una enumeración o una estructura.

¿O usted?

 typedef enum { c1, c2 } tMyEnum; typedef struct { int i; double d; } tMyStruct; 

puede ser mejor escrito como

 enum tMyEnum { c1, c2 } struct tMyStruct { int i; double d; }; 

¿Es eso correcto? ¿Qué hay de C?