Overview

The auto keyword changed its semantics starting from the C++11 standard. In this notebook, we will review its new semantics and examine its new flavors.

Using the auto keyword

The auto keyword changed its semantics starting from the C++11 standard. From C++11 onwards, the semantic of the keyword is automatic type deduction. In fact, from C++11 onwards, we have the following different flavors of the keyword [1]:

  • auto
  • const auto&
  • auto&
  • auto&&

Furthermore, we have decltype(auto). This post is a short guide on how to use auto and its various flavors.

Automatic type deduction

The first thing to note about auto is that it ise used for automatic type deduction. This means that we can write code like the following:

...
// before c++11
int x = 5;

//from c++11
auto x = 5;
...

Thus, using auto may help us to write cleaner and less cluttered code. This is emphasized particularly when we consider function signatures. Compare the code snippet below (example taken from [1]):

class Foo
{

int value()const{..}
const int& cref_value()const{...}
int& ref_value(){...}

};

with the following code snippet

class Foo
{

auto value()const{..}
auto& cref_value()const{...}
auto& ref_value(){...}

};

The latter API is obviously cleaner and simpler.The type returned is deduced by the compiler for us.


Remark

Althgough to a large extent using auto simplifies our code, overusing it can have the opposite result.


One other advantage of using auto is that we cannot leave the variable uninitialized. That is the following fails to compile.

...
auto x;
...

This is reasonable as the compiler uses the right hand side value to deduce the type and hence the memory size it has to allocate. If there isn't a value there is nothing to deduce from. Thus, uninitialized variables are not allowed when using auto and the good news are that the compilers let us know the exact line number in our code that this occurs.

const reference

const auto& has the ability to bind to anything [1]. The original object cannot be mutated via such a reference. Note that if the const reference is bound to a temporary object, the lifetime of the temporary will be extended to the lifetime of the reference [1].

Although we may be using auto& , it is possible that we end up with a const reference. For example

auto foo = Foo{};
auto& cref = cref_value();

We should however strive to be more explicit and for such cases simply use const auto& and use auto& to only denote mutable references [1].

Forwarding reference

Similar to auto&, auto&& can bind to anything. auto&& is called a forwardin or universal reference [1]. Similar to const auto&, auto&& extends the lifetime of a temporary. However, in contrast to const auto&, auto&& allows us to mutate the objects it references including the temporaries.


Remark

Note that auto&& and T&& are interpreted as forwarding references only when used in a function template where T is a template parameter of that function. However, using && with an explicit type e.g. std::vector<double>&& denotes an rvalue reference and does not have the properties of a forwarding reference [1].


References

  1. Bjorn Andrist, Viktor Sehr, C++ High Performance, 2nd Edition, Packt Publishing