auto
uses the same mechanism of type deduction as templates, the only exception that I am aware of being that of brace-init lists, which are deduced by auto
as std::initializer_list
, but non-deduced in a template context.
auto x = expression;
works by first stripping all reference and cv qualifiers from the type of the right hand side expression, then matching the type. For example, if you have const int& f(){...}
then auto x = f();
deduces x
as int
, and not const int&
.
The other form,
auto& x = expression
does not strip the cv-qualifiers, so, using the example above, auto& x = f()
deduces x
as const int&
. The other combinations just add cv qualifiers.
If you want your type to be always deduced with cv-ref qualifiers, use the infamous decltype(auto)
in C++14, which uses the decltype
type deduction rules.
So, in a nutshell, if you want copies, use auto
, if you want references, use auto&
. Use const
whenever you want additional const
-ness.
EDIT
There is an additional use case,
auto&& x = expression;
which uses the reference-collapsing rules, same as in the case of forwarding references in template code. If expression
is a lvalue, then x
is a lvalue reference with the cv-qualifiers of expression
. If expression
is a rvalue, then x
is a rvalue reference.