Estoy un poco confundido acerca de si debería usar typedef en C ++ y cuándo. Siento que es un acto de equilibrio entre legibilidad y claridad.
Aquí hay una muestra de código sin ningún tipo de definición:
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;
...
}
Bastante feo de la OMI. Así que agregaré algunos typedefs dentro de la función para que se vea mejor:
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;
...
}
El código sigue siendo un poco torpe, pero me deshago de la mayoría del material de pesadilla. Pero aún existen los iteradores de vector int, esta variante se deshace de ellos:
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;
...
}
Esto se ve limpio, pero ¿sigue siendo legible?
¿Cuándo debo usar un typedef? ¿Tan pronto como tenga un tipo de pesadilla? ¿Tan pronto como ocurre más de una vez? ¿Dónde debería ponerlos? ¿Debo usarlos en firmas de funciones o mantenerlos en la implementación?
c++
coding-style
futlib
fuente
fuente
typedef Input_iterator std::vector<int>::const_iterator;
está al revés#define
no es lo suficientemente bueno.Respuestas:
Su último ejemplo es muy legible, pero depende de dónde defina el typedef. Los typedefs de ámbito local (como en su segundo ejemplo) son IMVHO casi siempre una victoria.
Todavía me gusta su tercer ejemplo, pero es posible que desee pensar en el nombre y dar los nombres de los iteradores que indican la intención del contenedor.
Otra opción sería hacer una plantilla a partir de su función, para que también funcione con diferentes contenedores. En la línea de
que también está muy en el espíritu de la STL.
fuente
Piense en a
typedef
como el equivalente de declaración variable de una función: está ahí, así que ...Personalmente, me da vueltas si tengo que leer nombres de tipo largos como
std::vector<int>::const_iterator
repetidamente.Su tercer ejemplo no se repite innecesariamente y es más fácil de leer.
fuente
typedef
Las declaraciones tienen esencialmente el mismo propósito que la encapsulación. Por esa razón, casi siempre encajan mejor en un archivo de encabezado, siguiendo las mismas convenciones de nomenclatura que sus clases, porque:typedef
, es probable que las personas que llaman también lo hagan, especialmente como en su ejemplo donde se usa en los argumentos.Por otro lado, su código de memorización sería mucho más limpio si lo resumiera más, como:
fuente