typedef vs using em C++: o que escolher e como eles realmente diferem?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

typedef vs using em C++: guia completo para o desenvolvedor moderno

\n\n

Você já se perguntou por que em código C++ alguns desenvolvedores escrevem typedef e outros — using? Parece que ambos fazem a mesma coisa — criam aliases para tipos. Mas será que é realmente assim? Se você quer escrever código limpo e moderno e não cair em armadilhas de construções obsoletas, este artigo é para você.

\n\n

Vamos analisar como typedef e using diferem em C++, quando usar cada um e por que a comunidade C++ está cada vez mais inclinada ao using. Pronto? Vamos lá!

\n\n

Breve história: do C ao C++11

\n\n

typedef veio da linguagem C. É a forma clássica de declarar um alias para um tipo. Fica assim:

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

A sintaxe, para dizer o mínimo, não é a mais intuitiva. Isso é especialmente perceptível com ponteiros para funções — até desenvolvedores experientes às vezes hesitam ao ler tais declarações.

\n\n

No C++11, surgiu uma nova construção — using (ou declaração de alias). Ela parece muito mais natural:

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

Imediatamente fica claro: à esquerda — o nome, à direita — o tipo. Lê-se como uma "atribuição", o que é intuitivo para qualquer programador.

\n\n

Principal diferença: trabalho com templates

\n\n

Aqui está a diferença mais importante entre typedef e using. using suporta alias templates (aliases de template), enquanto typedef não.

\n\n

Vamos ver um exemplo. Suponha que você queira criar um alias para std::unique_ptr com um deletador personalizado:

\n\n
// Com using — fácil e elegante\ntemplate <typename T>\nusing CustomPtr = std::unique_ptr<T, void(*)(T*)>;\n\n// Com typedef — impossível diretamente!\n// É preciso criar wrappers através de structs\ntemplate <typename T>\nstruct CustomPtrOld {\n    typedef std::unique_ptr<T, void(*)(T*)> type;\n};\n\n// Uso:\nCustomPtr<int> ptr1;                    // using — simples\nCustomPtrOld<int>::type ptr2;           // typedef — complicado
\n\n

Percebe a diferença? using torna o código mais limpo e curto. E se você precisar usar esse alias dentro de uma classe ou função template, a diferença fica ainda mais evidente:

\n\n
template <typename T>\nclass Container {\npublic:\n    // Com using\n    using Ptr = CustomPtr<T>;\n    \n    // Com typedef — precisa de typename e ::type\n    typedef typename CustomPtrOld<T>::type OldPtr;\n    \nprivate:\n    Ptr data;\n    OldPtr oldData;\n};
\n\n

Legibilidade do código: vencedor óbvio

\n\n

Mesmo para tipos simples, using ganha em legibilidade. Compare:

\n\n
// Com typedef — não está claro onde está o nome e onde está o tipo\ntypedef std::map<std::string, std::vector<int>> StringToIntVectorMap;\n\n// Com using — tudo é óbvio\nusing StringToIntVectorMap = std::map<std::string, std::vector<int>>;
\n\n

Ao ler o código, seu olho naturalmente escaneia a construção da esquerda para a direita. using segue esse princípio: primeiro o nome, depois o tipo. typedef força você a ler primeiro o tipo e depois o nome — isso contradiz a intuição.

\n\n

Ponteiros para funções: o grande problema do typedef

\n\n

Ponteiros para funções são, talvez, a parte menos amada do C++ para muitos desenvolvedores. E typedef os torna ainda mais confusos:

\n\n
// typedef — leia como um feitiço\ntypedef void (*Callback)(int, const std::string&);\n\n// using — como uma variável comum\nusing Callback = void (*)(int, const std                

Blogs

Book Recommendations