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.
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!
Breve historia: de C a C++11
\n\ntypedef proviene del lenguaje C. Es la forma clásica de declarar un alias para un tipo. Se ve así:
\n\ntypedef unsigned long long ULL;\ntypedef std::vector<std::string> StringVector;\ntypedef void (*FunctionPtr)(int, double);\n\nLa 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\nEn C++11 apareció una nueva construcción: using (o declaración de alias). Se ve mucho más natural:
\n\nusing ULL = unsigned long long;\nusing StringVector = std::vector<std::string>;\nusing FunctionPtr = void (*)(int, double);\n\nSe 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\nLa principal diferencia: trabajo con plantillas
\n\nAquí reside la diferencia más importante entre typedef y using. using admite alias templates (alias de plantillas), mientras que typedef no.
Veamos un ejemplo. Supongamos que desea crear un alias para std::unique_ptr con un eliminador personalizado:
// 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:
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\nLegibilidad del código: un ganador evidente
\n\nIncluso para tipos simples, using gana en legibilidad. Compare:
// 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\nCuando 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.
Punteros a funciones: el dolor de typedef
\n\nLos punteros a funciones son, quizás, la parte menos querida de C++ para muchos desarrolladores. Y typedef los hace aún más confusos:
// 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