typedef vs using en C++: ¿qué elegir y en qué se diferencian realmente?

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

typedef vs using en C++: guía completa para el desarrollador moderno

\n\n

¿Alguna vez se ha preguntado por qué en el código C++ algunos desarrolladores escriben typedef y otros using? Parece que ambos hacen lo mismo: crear alias para tipos. Pero, ¿es realmente así? Si desea escribir código limpio y moderno y no caer en trampas de construcciones obsoletas, este artículo es para usted.

\n\n

Analizaremos en qué se diferencian typedef y using en C++, cuándo usar cada uno y por qué la comunidad C++ se inclina cada vez más hacia using. ¿Listo? ¡Comencemos!

\n\n

Breve historia: de C a C++11

\n\n

typedef proviene del lenguaje C. Es la forma clásica de declarar un alias para un tipo. Se ve así:

\n\n
typedef unsigned long long ULL;\ntypedef std::vector<std::string> StringVector;\ntypedef void (*FunctionPtr)(int, double);
\n\n

La sintaxis, por decirlo suavemente, no es la más intuitiva. Esto se nota especialmente con los punteros a funciones: incluso los desarrolladores experimentados a veces se atascan al leer dichas declaraciones.

\n\n

En C++11 apareció una nueva construcción: using (o declaración de alias). Se ve mucho más natural:

\n\n
using ULL = unsigned long long;\nusing StringVector = std::vector<std::string>;\nusing FunctionPtr = void (*)(int, double);
\n\n

Se ve de inmediato: a la izquierda, el nombre; a la derecha, el tipo. Se lee como una "asignación", lo que es intuitivamente comprensible para cualquier programador.

\n\n

La principal diferencia: trabajo con plantillas

\n\n

Aquí reside la diferencia más importante entre typedef y using. using admite alias templates (alias de plantillas), mientras que typedef no.

\n\n

Veamos un ejemplo. Supongamos que desea crear un alias para std::unique_ptr con un eliminador personalizado:

\n\n
// Con using — fácil y elegante\ntemplate <typename T>\nusing CustomPtr = std::unique_ptr<T, void(*)(T*)>;\n\n// Con typedef — ¡imposible directamente!\n// Hay que crear envoltorios con estructuras\ntemplate <typename T>\nstruct CustomPtrOld {\n    typedef std::unique_ptr<T, void(*)(T*)> type;\n};\n\n// Uso:\nCustomPtr<int> ptr1;                    // using — simple\nCustomPtrOld<int>::type ptr2;           // typedef — engorroso
\n\n

¿Nota la diferencia? using hace el código más limpio y corto. Y si necesita usar dicho alias dentro de una clase o función plantilla, la diferencia se vuelve aún más notable:

\n\n
template <typename T>\nclass Container {\npublic:\n    // Con using\n    using Ptr = CustomPtr<T>;\n    \n    // Con typedef — se necesita typename y ::type\n    typedef typename CustomPtrOld<T>::type OldPtr;\n    \nprivate:\n    Ptr data;\n    OldPtr oldData;\n};
\n\n

Legibilidad del código: un ganador evidente

\n\n

Incluso para tipos simples, using gana en legibilidad. Compare:

\n\n
// Con typedef — no está claro dónde está el nombre y dónde el tipo\ntypedef std::map<std::string, std::vector<int>> StringToIntVectorMap;\n\n// Con using — todo es obvio\nusing StringToIntVectorMap = std::map<std::string, std::vector<int>>;
\n\n

Cuando lee código, su ojo escanea naturalmente la construcción de izquierda a derecha. using sigue este principio: primero el nombre, luego el tipo. typedef, en cambio, le obliga a leer primero el tipo y luego el nombre, lo que contradice la intuición.

\n\n

Punteros a funciones: el dolor de typedef

\n\n

Los punteros a funciones son, quizás, la parte menos querida de C++ para muchos desarrolladores. Y typedef los hace aún más confusos:

\n\n
// typedef — léalo como un hechizo\ntypedef void (*Callback)(int, const std::string&);\n\n// using — como una variable normal\nusing Callback = void (*)(int, const std                

Blogs

Book Recommendations