Automatic Type Deduction using auto
This lesson covers how we can ask the compiler to infer what types we are using through the auto
keyword
When we're initializing a variable with a value, the compiler can automatically infer the type our variable should have. We can ask the compiler to infer this using the auto
keyword.
Below, we're initializing MyNumber
using an int
literal, so the compiler will set MyNumber
's type to int
:
// This will create an int
auto MyNumber { 5 };
Most editors, including Visual Studio, will let us inspect what the type was deduced to be by hovering over the variable name.

Types can also automatically be deduced in a variety of contexts. For example, when initializing a variable using an expression, such as a function call, its type can also be deduced from the return type of that expression.
Below, GetFloat()
's return type is float
, so MyNumber
will have a type of float
:
float GetFloat() {
return 3.14;
}
// Will be float
auto MyNumber { GetFloat() };
Dynamic Typing vs auto
Some may have experience with other programming languages that have a dynamic type system. There, the type of a variable can be changed during our program's execution. The following example is valid JavaScript:
var MyVariable = 10;
MyVariable = "Hello World";
It is important to note that auto
is not an implementation of dynamic types. auto
will fix the variable type as soon as it is created. Then, any future assignment will try to convert the new value to that type.
Below, we create an int
variable, and then try to update it by converting the new value to that same type. In this case, the conversion is impossible, so we get a compilation error:
auto MyVariable { 10 };
MyVariable = "Hello World";
error: cannot convert from 'const char [12]' to 'int'
For the same reason, we also can't do this:
auto MyVariable;
error: 'MyVariable': a symbol whose type contains 'auto' must have an initializer
If we try to use auto
without providing an initial value, the compiler cannot infer what to set its type to.
C++ does support dynamic typing, and we cover it in the advanced course. However, C++ has a strong type system, and it's generally designed such that code written in C++ will be using that type system heavily.
Function Return Types Using auto
The auto
keyword can also be used to automatically determine the return type of a function. This can be inferred by how the function uses the return
statement.
Below, GetDouble()
will have its return type correctly deduced to double
., as we're return
ing a double
literal.
Because of this, MyNumber
will also have its return type inferred as a double
:
auto GetDouble() {
return 3.14;
}
auto MyNumber { GetDouble() };
This depends on all of our return
statements deducing to the same type. The following will not work, as the compiler cannot determine whether the return type should be float
or double
:
auto GetDouble() {
if (SomeCondition) {
return 9.8f;
}
return 3.14;
}
error: 'double': all return expressions must deduce to the same type: previously it was 'float'
If we convert all return types to a consistent type, our code will compile again. In the following example, the return type of GetDouble
will correctly be inferred as double
:
auto GetDouble() {
if (SomeCondition) {
return static_cast<double>(9.8f);
}
return 3.14;
}
Were we to specify the return type, the compiler would implicitly convert the returned values to that type, as we've seen before.
Below, our code will compile, with our function returning a double
with the value of 9.8
if SomeCondition
is true:
double GetDouble() {
if (SomeCondition) {
return 9.8f;
}
return 3.14;
}
Function Paramaters With auto
(C++20)
As of C++20, auto
can also be used with function parameters:
auto Add(auto x, auto y) {
return x + y;
}
auto NumberA { Add(1, 2) };
auto NumberB { Add(1, 2.0) };
We're calling the Add()
function with two integers, so x
and y
in that function will have the int
type.
Then, we return the result of summing two int
objects, therefore the return type of Add()
will also be deduced to be an int
.
Finally, because NumberA
is being initialized with an expression that returns an int
, its type will also be an int
.
The same process applies to NumberB
, which will have a type of double
.
Qualifiers: auto
Pointers, auto
References
As with any type, we can add qualifiers to our auto
declarations. For example, we can create references and pointers to automatically deduced types:
int x { 5 };
// Reference to an automatically deduced type
auto& ReferenceToX { x };
// Pointer to an automatically deduced type
auto* PointerToX { &x };
Should We Use auto
?
Generally, we should only use auto
if it makes our code clearer. The main scenario where this is the case is where it reduces unnecessary noise.
Typically this involves scenarios where we're repeating a complex type multiple times within the same expression:
SomeNamespace::SomeType MyObject {
static_cast<SomeNamespace::SomeType>(Target)
};
Adding auto
here will reduce the noise, and not hide the type as we're already specifying it in the static_cast
parameter anyway:
auto MyObject {
static_cast<SomeNamespace::SomeType>(Target)
};
Whilst it can save a few keystrokes, using auto
can make our code more difficult to read, especially as it gets more complicated.
Generally, auto
should not be used if our only reason is to avoid some keystrokes. In the future, we'll see more and more complex types. If our type is verbose and repeated often in our file, we can be tempted to use auto
.
But we should consider a type alias instead. After adding the following using
statement, we can refer to our type simply as Party
, rather than being tempted to use auto
:
using Party =
std::vector<std::pair<Character*, bool>>;
Party MyParty{ GetParty() };
There are two main problems with auto
:
Determining the Type Requires Tool Assistance
We've seen how in most IDEs, we can easily hover over a type to determine its type, even if the code is using auto
. However, hovering is still slower than reading, and code isn't always opened in an IDE.
In larger projects, code is often read in tools that don't provide the functionality of IDEs. A common example is source control applications such as GitHub.
Determining the Type Requires our Code be Compilable
Secondly, even if our editors can show us how auto
is being interpreted, that capability often requires our code to be in a compilable state.
If we introduce an issue that prevents code from being compilable, we often lose visibility on the types we were relying on being deduced by the compiler. This can make the issue even more difficult to debug.
In the remainder of this course and future courses, we adopt a fairly conservative use of auto
. We avoid it by default but will use it if we think it makes the code clearer.
This generally falls in line with Google's style guide:
Use type deduction only to make the code clearer or safer, and do not use it merely to avoid the inconvenience of writing an explicit type.
When judging whether the code is clearer, keep in mind that your readers are not necessarily on your team, or familiar with your project, so types that you experience as unnecessary clutter will very often provide useful information to others
However, many others recommend avoiding auto
as much as possible:
Always be explicit about the type you're initializing. This means that the type must be plainly visible to the reader.
...
It's very important that types are clearly visible to someone who is reading the code. Even though some IDEs are able to infer the type, doing so relies on the code being in a compilable state. It also won't assist users of merge/diff tools, or when viewing individual source files in isolation, such as on GitHub.
Summary
This lesson introduced the concept of automatic type deduction, explaining how the auto
keyword enables the compiler to infer variable types. The key topics points included:
- The
auto
keyword allows the compiler to deduce the type of a variable from its initializer. auto
is distinct from dynamic typing found in languages like JavaScript; once a type is deduced, it cannot be changed.- The lesson explains how
auto
can be used for function return types and function parameters. - It discusses the use of
auto
in creating function templates, where the compiler generates functions based on the template's usage. - We should use
auto
sparingly and only to improve clarity and readability, not simply convenience.
Constants and const
-Correctness
Learn the intricacies of using const
and how to apply it in different contexts