Resposta curta: mais completamente, minha opinião atual sobre auto
é que você deve usar auto
por padrão, a menos que você queira explicitamente uma conversão. (Um pouco mais precisamente, "... a menos que você queira explicitamente se comprometer com um tipo, o que quase sempre é porque você quer uma conversão.")
Resposta e justificativa mais longas:
Escreva um tipo explícito (em vez de auto
) apenas quando você realmente quiser se comprometer explicitamente com um tipo, o que quase sempre significa que você deseja obter explicitamente uma conversão para esse tipo. No topo da minha cabeça, lembro-me de dois casos principais:
- (Comum) A surpresa
initializer_list
queauto x = { 1 };
deduzinitializer_list
. Se você não quiserinitializer_list
, diga o tipo, ou seja, solicite explicitamente uma conversão. - (Rare) O caso de modelos de expressão, como
auto x = matrix1 * matrix 2 + matrix3;
, captura um tipo auxiliar ou de proxy não destinado a ser visível para o programador. Em muitos casos, é bom e benigno capturar esse tipo, mas às vezes, se você realmente quiser que ele colapse e faça o cálculo, diga o tipo - ou seja, solicite explicitamente uma conversão.
Use rotineiramente auto
por padrão, porque usar auto
evita armadilhas e torna seu código mais correto, mais sustentável, robusto e mais eficiente. Aproximadamente na ordem do mais para o menos importante, no espírito de "escrever para clareza e correção primeiro":
-
Exatidão: Usar
auto
garante que você terá o tipo certo. Como diz o ditado, se você se repetir (diga o tipo de forma redundante), você pode e irá mentir (errar). Aqui está um exemplo usual:void f( const vector<int>& v ) { for( /*…*
- neste momento, se você escrever o tipo do iterador explicitamente, você quer se lembrar de escreverconst_iterator
(não é?), Enquantoauto
apenas acerta. -
Mantenabilidade e robustez: Usar
auto
torna seu código mais robusto em relação a alterações, porque quando o tipo da expressão é alterado,auto
continuará a ser resolvido para o tipo correto. Se você, em vez disso, se comprometer com um tipo explícito, a alteração do tipo da expressão injetará conversões silenciosas quando o novo tipo for convertido para o tipo antigo ou intervalos de compilação desnecessários quando o novo tipo continuar funcionando como o tipo antigo, mas não convertido para o antigo tipo (por exemplo, quando você altera ummap
para umunordered_map
, o que é sempre bom se você não estiver confiando no pedido, usandoauto
para seus iteradores, você alternará facilmente demap<>::iterator
paraunordered_map<>::iterator
, mas usarmap<>::iterator
em todos os lugares explicitamente significa que você estará desperdiçando seu valioso tempo em uma ondulação mecânica de código, a menos que um estagiário esteja passando e você possa impingir o trabalho chato sobre eles). -
Desempenho: Como
auto
garante que nenhuma conversão implícita ocorrerá, ela garante melhor desempenho por padrão. Se, em vez disso, você disser o tipo e exigir uma conversão, muitas vezes você receberá uma conversão silenciosamente, independentemente do que esperava ou não. -
Usabilidade: Usar
auto
é sua única boa opção para tipos difíceis de serem soletrados e inutilizáveis, como lambdas e ajudantes de modelo, além de recorrer a expressõesdecltype
repetitivas ou indiretas menos eficientes, comostd::function
. -
Conveniência: E, sim,
auto
é menos digitação. Eu mencionei isso por completo porque é um motivo comum para gostar, mas não é o maior motivo para usá-lo.
Por isso: Prefiro dizer auto
por padrão. Ele oferece tanta simplicidade, desempenho e clareza que você só está se machucando (e os futuros mantenedores do seu código) se você não o fizer. Somente se comprometa com um tipo explícito quando você realmente quiser, o que quase sempre significa que você quer uma conversão explícita.
Sim, existe (agora) um GotW sobre isso.