A palavra-chave auto em C++ permite ao compilador fazer uma inferência de tipo, isto é, detectar automaticamente qual é o tipo da expressão que vem depois dela. Assim sendo, o auto permite, por exemplo, que o compilador detecte automaticamente o tipo de um variável.
Essa capacidade do auto torna-se especialmente útil quando o tipo da variável que se deseja inicializar é complicado de se escrever, como o tipo de it
no exemplo 1 (ao invés de escrever vector<int>::iterator, escrevi apenas auto).
Exemplo 1 – Dedução simples usando auto em C++
#include <iostream> #include <string> #include <vector> using namespace std; int main() { vector<int> iVec {10, 20, 30}; auto it = iVec.begin(); // auto dispensa escrever o tipo vector<int>::iterator auto x {22.5}; cout << "Tipo de x: " << typeid(x).name() << endl; cout << "Tipo de it: " << typeid(it).name() << endl; }
Como podemos ver na saída do exemplo acima, o tipo de x
foi deduzido como double e o tipo de it
como vector<int>::iterator (ainda que o seu nome na saída do programa seja difícil de se ler).
Referências e const com auto em C++
Apesar de permitir que o compilador deduza o tipo das variáveis corretamente, é importante notar que auto remove todos os indicadores de referência (&) e todos os const dos tipos deduzidos. Ou seja, se desejamos criar uma variáveis constante ou uma referência, é preciso adicionar manualmente const e & ao auto.
Vejamos um exemplo desse uso do auto a seguir.
Exemplo 2 – Referências e const removidos com auto em C++
#include <iostream> #include <string> using namespace std; const string mensagem {"Oi, meu chapa"}; const string& obterMensagem() { return mensagem; } int main() { auto x { obterMensagem() }; // Tipo de x: string const auto& y { obterMensagem() }; // Tipo de y: const string & }
No exemplo 2, a variável x
é criada a partir do retorno da função obterMensagem()
, que retorna uma referência constante para a variável global mensagem
. Todavia, o tipo de x
é apenas string, visto que o auto remove o const e a referência do tipo deduzido.
Para obter o tipo const string& usando auto, eu tive que manualmente adicionar esses indicadores ao auto (linha 15, exemplo 2).
auto remove os indicadores const e de referência (&). Portanto, se quiser criar variáveis desses tipos usando auto, adicione os indicadores manualmente.
Ponteiros com auto em C++
Ao contrário do que acontece com const e referências, auto não remove o * dos tipos ponteiros, ou seja, auto detecta corretamente os tipos ponteiros simples. Assim, a variável y
a seguir tem o tipo correto de int*.
int x {10}; auto y = &x;
Todavia, a dedução de tipos ponteiro com auto apenas (sem adicionar-lhe nada) escode uma pegadinha quando se deseja criar ponteiros para tipos constantes (por exemplo, const int * – ponteiro para int constante). Ao invés de deduzir que o tipo é const, auto deduz que o ponteiro é const! Para revisar os diferentes tipos de ponteiros, visite nosso artigo sobre o assunto.
Vejamos esse efeito no exemplo 3.
Exemplo 3 – Ponteiros e auto em C++
#include <iostream> #include <string> using namespace std; int main() { const int x { 10 }; auto iPtr { &x }; // int* const auto iConstPtr { &x }; // int* const auto const iConstPtr2 { &x }; // int* const const auto* iPtrToConst { &x }; // const int * auto* const iConstPtr3 { &x }; // int* const const auto* const iConstPtrToConst { &x }; // const int * const }
No exemplo acima, vemos que a variável iConstPtr
é do tipo int* const, isto é: ponteiro constante para int. Provavelmente não era isso que você queria fazer, não é? Queremos um ponteiro para int constante. Veja ainda que não adianta mudar o const de lugar, como fiz com iConstPtr2
: o resultado é sempre o mesmo, int* const.
Para se obter um const int*, é preciso adicionar manualmente o * na frente do auto, para indicar que o tipo deduzido é um ponteiro. Fazendo assim, é possível obter const int*, como em iPtrToConst
(linha 12). Também é possível obter quaisquer variações que se deseje movendo o const de lugar, como vemos com iConstPtr3
e iConstPtrToConst
.
A seguir está um resumo dos tipos de cada um dos ponteiros do exemplo 3.
Tipo na declaração da variável | Tipo deduzido da variável | Nome do tipo |
auto iPtr | int* | ponteiro para int |
const auto iConstPtr | int* const | ponteiro constante para int |
auto const iConstPtr2 | int* const | ponteiro constante para int |
const auto* iPtrToConst | const int* | ponteiro para int constante |
auto* const iConstPtr3 | int* const | ponteiro constante para int |
const auto* const iConstPtrToConst | const int* const | ponteiro const para int const |
Best practices
Sempre que for deduzir o tipo de um ponteiro com auto, use o indicador * para evitar confusões como aquelas mostradas na tabela acima.
Próximos assuntos
Chegamos ao fim deste artigo, e eu espero que você tenha entendido como funciona a palavra-chave auto na dedução automática de tipos de variáveis, e que você tenha ficado atento ao detalhes no uso do auto com variáveis de tipo constante, referência e ponteiros.
Os próximos passos no seu trajeto para dominar o uso do auto em C++ é entender como ele funciona para se deduzir tipos de retorno de funções template, e como utilizá-lo em conjunto com o decltype.
Se não quiser perder esses artigos e ficar de olho no que postamos aqui, se inscreva na nossa newsletter para receber os artigos direto no seu email (você pode se desinscrever quando quiser).
Até à próxima!
Sou apaixonado por tecnologia, literatura e também filosofia. O cultivo dessas paixões ao longo da minha trajetória me inspiraram a compartilhar aquilo que aprendo com os outros da maneira mais clara que eu possa. Sou formado em Engenharia Elétrica no Brasil, e também sou engenheiro formado na França. Trabalho atualmente como programador C++ em uma multinacional francesa, uma das maiores empresas de TI do mundo.