typename vs class em templates C++: guia completo

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

O que está por trás das palavras "typename" e "class"? Diferenças que você precisa saber

\n\n

Se você já escreveu templates em C++, certamente já se deparou com duas palavras-chave aparentemente intercambiáveis: typename e class. Parece um detalhe, mas no Stack Overflow essa pergunta acumulou milhares de visualizações. Por quê? Porque por trás da aparente simplicidade existe uma armadilha que pode quebrar a compilação do seu código.

\n\n

Neste artigo, vamos entender de uma vez por todas: qual a diferença entre typename e class em templates C++, quando podem ser usados como sinônimos e quando isso levará a um erro. Sem enrolação — apenas código, exemplos e regras claras.

\n\n

Resposta rápida: afinal, existe diferença?

\n\n

A resposta mais popular no Stack Overflow é: para declarar parâmetros de template, não há diferença. Você pode escrever:

\n\n
template <typename T> void foo(T t);
\n

ou

\n
template <class T> void foo(T t);
\n\n

Ambas as opções são totalmente válidas e fazem a mesma coisa: declaram um parâmetro de template T. Historicamente, class apareceu primeiro (no C++98), e typename foi adicionado depois para enfatizar que o parâmetro pode ser não apenas uma classe, mas qualquer tipo (int, double, ponteiro, etc.).

\n\n

No entanto, o diabo está nos detalhes. Existe um cenário onde typename é obrigatório e class não funciona. E esse cenário são os nomes dependentes (dependent names).

\n\n

A principal armadilha: tipos dependentes (dependent types)

\n\n

Imagine a situação: você está escrevendo um template e, dentro dele, acessa um tipo aninhado ao parâmetro do template. Por exemplo, você tem um contêiner e quer obter seu iterador:

\n\n
template <typename Container>\nvoid printFirst(const Container& c) {\n    Container::const_iterator it = c.begin(); // ERRO!\n    std::cout << *it;\n}
\n\n

Por que isso não compila? Porque Container::const_iterator é um nome dependente. O compilador, durante a análise sintática, não sabe o que é Container. Pode ser uma classe ou o nome de uma variável estática? Por padrão, o C++ assume que Container::const_iterator é o nome de uma variável (ou membro estático), e não um tipo. E apenas a palavra-chave typename diz ao compilador: "Ei, isso é um tipo!".

\n\n

Corrigindo:

\n\n
template <typename Container>\nvoid printFirst(const Container& c) {\n    typename Container::const_iterator it = c.begin(); // OK!\n    std::cout << *it;\n}
\n\n

Importante: aqui, class não funciona. Escrever class Container::const_iterator é um erro de sintaxe. typename é a única opção correta.

\n\n

Quando usar typename em vez de class?

\n\n

Lembre-se da regra simples: typename é usado em dois casos:

\n
    \n
  • Como parâmetro de template (sinônimo de class): template <typename T>
  • \n
  • Para indicar que um nome dependente é um tipo: typename T::value_type
  • \n
\n\n

Já class é usado apenas no primeiro caso. E muitos programadores C++ preferem typename para parâmetros, para não confundir com a declaração de uma classe.

\n\n

Exemplo completo com explicações

\n\n

Vamos analisar um código real que demonstra a diferença entre typename e class em templates C++ na prática:

\n\n
#include <iostream>\n#include <vector>\n#include <list>\n\n// Passo 1: template com class (ou typename — tanto faz)\ntemplate <class T>\nclass MyContainer {\npublic:\n    // Passo 2: usamos typename para o tipo dependente\n    // T::value_type é um tipo, não uma                

Blogs

Book Recommendations