2010-02-04 13 views
6

Últimamente me he encontrado con la siguiente construcción en el código:¿Cuál es el punto de "typedef algo tipo"?

typedef sometype sometype; 

Tener en cuenta por favor que "sometype" significa absolutamente el mismo tipo sin ningún tipo de adiciones como "estructura", etc.

Me pregunto para qué puede ser útil?

UPD: Esto funciona solo para los tipos definidos por el usuario.

UPD2: El código real se encontraba en un contexto de la plantilla de esta manera:

template <class T> 
struct E 
{ 
    typedef T T; 
    ... 
} 
+6

¿Estás seguro de que no dice: 'typedef struct sometype sometype;'? –

+2

por lo que un ejemplo concreto sería 'typedef char char'? – SiegeX

+0

Me pregunté sobre el código de muestra, no creí que se pudiera compilar. Probado. Puede: 'struct A {int x; }; int main() {typedef A A; A a; return 0; } ' – Notinlist

Respuesta

7

¿Qué tal hacer que los parámetros de Plantilla sean visibles para entidades externas?

template <class Foo> 
struct Bar 
{ 
    typedef Foo Foo; 
}; 

int main() 
{ 
    Bar<int>::Foo foo = 4; 
} 

Nota: esto no está permitido en C++ estándar, pero es específico para MSVC. Ver comentarios.

+4

Entonces, ¿por qué no eliminarlo? –

+0

Bastante seguro de que funciona en algunos compiladores, por lo que si el OP ha visto este código, esta podría ser la razón, por lo que sigue siendo una respuesta válida a su pregunta. – jalf

+3

@Niel: Porque si lo elimino, algún otro tipo inteligente pensará en lo mismo y lo publicará nuevamente. A veces vale la pena saber cuál es la respuesta incorrecta. –

6

En C++, se puede poner un typedef en un espacio de nombres o de clase, y luego hacer referencia a ella en relación con ese espacio de nombres o de clase, que puede ser útil si el tipo real puede cambiar en el futuro.

p. Ej.

class IntHolder 
{ 
    public: 
     typedef int int; 
     IntHolder::int i; 
}; 
... 
IntHolder foo; 
IntHolder::int i = foo.i; 

(NB: No he comprobado que es bastante la sintaxis correcta - pero espero que usted consigue la idea)

Si en algún momento futuro en realidad se desea mantener long en IntHolder sólo tiene que cambiar el código IntHolder.

Ahora, normalmente nombra el tipo de forma diferente, pero ¿quizás puede hacer lo anterior?

+0

Honorario +1 para un escenario de uso decente. Puedo ver que esto sucede fácilmente para los tipos menos integrados que 'int'. –

+0

No parece compilar más que todas las otras respuestas que sugieren esto (con GCC y Comeau). - Si se supone que la clase solo tiene un typedef, simplemente use 'typedef X type;', para que la gente no tenga que adivinar cada vez. Quiero decir, 'IntHolder :: int' resultaría ser' largo'? ¿Por qué llamarlo ** int ** y no 'IntHolder :: type'? – UncleBens

+0

No lo probé, y me alegro de que no lo haya hecho porque habría golpeado a gcc negándolo, mientras que el compilador de OP (VS) logró compilar la versión de la plantilla. –

6

Tengo una teoría. Podría ser el resultado de algunas refactorizaciones. Por ejemplo, un tipo de plantilla no se convierte en una plantilla.

typedef SomeCleverTemplate<Rocket> SuperThing; 

Luego se suprime la plantilla, por culpa no hubiera ningún otro uso de ella en el código, y por sólo para estar seguro que sustituyen cada SomeCleverTemplate<Rocket>-SuperThing.

typedef SuperThing SuperThing; 

¿Tiene sentido en el contexto real?

+0

Honorario +1 para "contexto real de demasiada automatización". Lo siento, no es un +1 real, estoy fuera por las próximas 12 horas. –

+0

¿Y por qué no funcionaría sin un typedef? –

+0

Sería. Creo que puedes borrar esa línea del código. – Notinlist

7

Dada su información adicional acerca de las plantillas, ahora podemos responder.

El caso de uso es cuando desea especializarse en el tipo de plantilla. Un ejemplo típico es el siguiente:

template <typename T> 
struct nonconst { 
    typedef T t; 
}; 

template <typename T> 
struct nonconst<T const> { 
    typedef T t; 
}; 

Esto permite efectivamente a eliminar el calificador const de cualquier tipo:

nonconst<int>::t x; 
nonconst<int const>::t y; 
assert(typeid(x) == typeid(int)); 
assert(typeid(y) == typeid(int)); 

Hay muchos casos de uso similares, por ejemplo, para agregar (o eliminar) el calificador de puntero de un tipo, proporcionar valores predeterminados y especializaciones para ciertos tipos, etc.

Sin embargo, observe la diferente carcasa de los nombres! Los tipos iguales en typedef T T son C++ ilegales. [mi error: §7.1.3.2] Por otra parte, el estándar de-hecho de nomenclatura (cementada por su uso en bibliotecas Boost) es llamar el nombre del tipo de alias type, por ejemplo:

typedef T type; 
+0

"Los tipos iguales en typedef T T son ilegales" - esto es incorrecto. Ver 7.1.3.2 en el estándar C++ '03. –

+0

@Alex: no estaba al tanto de eso. Sin embargo, 'g ++' 4.4.2 ('-pedantic') rescata cuando utilizo una carcasa idéntica en el código anterior. Entonces, ¿esto es un error de compilación? –

+0

Lo siento, creo que el gotcha puede estar en la observación "sin alcance de clase". Comeau Online tampoco compila esto, pero VC2008 sí. No pude encontrar el lugar en el estándar que explícitamente lo desaprobaría (¿alguien?), Por lo que puede ser definido por la implementación. –

1

A medida que como ya se ha ha mencionado, funciona especialmente bien dentro de una plantilla:

template <class Foo> 
struct Bar 
{ 
    typedef Foo Foo; 
}; 

Pero también puede ser combinado con la plantilla de especialización:

template <class Foo> 
struct Bar<Foo*> 
{ 
    typedef Foo Foo; 
}; 

Ahora, puedo hacer:

Bar<int>::Foo i = 0; 
Bar<int*>::Foo j = i; 

Bar se comporta por lo tanto efectivamente como un tipo de tipo envoltura, que puede ser importante para su interfaz (si hay un bool equals(Foo i) const por ejemplo).

Por lo general, el nombre elegido tiene algún significado value_type por ejemplo ...

0

Nueva idea! Ciertos clubes de programación como el uso extensivo de typedefs ...

zoo/animales/types.h:

namespace zoo 
{ 
    namespace animals 
    { 
     typedef size_t Count; 
     // ... 
    } // namespace animals 
} // namespace zoo 

zoo/animales/zebra.h:

#include "zoo/animals/types.h" 

namespace zoo 
{ 
    namespace animals 
    { 
     class Zebra { 
     public: 
      typedef Count Count; 
      Count getLegCount() const; 
      // ... 
     }; // class Zebra 
    } // namespace animals 
} // namespace zoo 

main.cpp:

#include "zoo/animals/zebra.h" 

int main() 
{ 
    typedef zoo::animals::Zebra Zebra; 
    Zebra z; 
    Zebra::Count n = z.getLegCount(); 
    // Not as zoo::animals::Count 
    // No using namespace zoo::animals required, 
    // we are using just one item from there, the Zebra. 
    // Definition of Zebra::Count may change, your usage remains robust. 
    return 0; 
} 

Acabo de tener una situación similar en mi lugar de trabajo. La traducción puede ser un poco tonta, pero quería presentarla con prisa.