C++ auto type deduction
auto asks the compiler to deduce a type from an initializer. The variable still has one fixed compile-time type; C++ does not become dynamically typed.
Brief example
Every declaration needs an initializer so the compiler has a type to deduce:
Why use auto?
Use auto when the initializer already makes the type clear or when spelling the type adds noise:
An explicit type is often clearer when the type communicates an important unit, range, or conversion:
auto is a readability tool, not a rule that every type must be hidden.
Value, reference, and const deduction
Plain auto creates a new value. It drops top-level const and does not keep a reference from the initializer.
Add qualifiers according to the behavior you need:
| Declaration | Meaning |
|---|---|
auto value = expression; |
Make a copy or move a new value. |
auto& value = expression; |
Create a modifiable reference. |
const auto& value = expression; |
Read without copying; can bind to a temporary. |
auto&& value = expression; |
Preserve the expression's value category during deduction. |
Start with intent
Use auto for an independent value, auto& to modify the original, and const auto& to read a potentially expensive value without copying it.
Loops
const auto& is a useful default for reading container elements:
Use auto& when the loop must modify each element:
Use plain auto only when you intentionally want a copy of every element.
Function return types
Since C++14, a function can deduce its return type from its return statements:
All return paths must deduce the same type. The function definition also normally needs to be visible before code calls it because the compiler must see the body to know the return type.
Use an explicit return type when it documents the interface better or when implicit conversions between return expressions are intended.
Generic lambdas
C++14 also allows auto in lambda parameters:
The compiler creates a suitable call operator for each compatible argument-type combination.
auto and structured bindings
Structured bindings use auto to deduce the decomposed element types:
Use auto& or const auto& when the bindings should refer to the original object. See C++ structured bindings for the complete lesson.
Braced initialization
These similar-looking declarations deduce different types:
Mixed element types cannot produce one initializer-list type:
Prefer direct initialization such as auto value = Type{...} when the intended type should be obvious.
decltype(auto)
decltype(auto) follows decltype rules and can preserve references that plain auto would discard:
This is useful in forwarding code, but it is easy to return a dangling reference. Prefer an explicit return type unless preserving the exact expression type is necessary.
Common mistakes
- Declaring
autowithout an initializer. - Assuming plain
autokeeps a reference or top-levelconst. - Copying large elements in a loop when
const auto&was intended. - Hiding a meaningful conversion or unit behind
auto. - Expecting one
autovariable to change type after declaration. - Accidentally deducing
std::initializer_listwithauto value = {...}.