auto and auto && cover most of the cases:
-
Use
autowhen you need a local copy. This will never produce a reference. The copy (or move) constructor must exist, but it might not get called, due to the copy elision optimization. -
Use
auto &&when you don’t care if the object is local or not. Technically, this will always produce a reference, but if the initializer is a temporary (e.g., the function returns by value), it will behave essentially like your own local object.Also,
auto &&doesn’t guarantee that the object will be modifiable, either. Given aconstobject or reference, it will deduceconst. However, modifiability is often assumed, given the specific context.
auto & and auto const & are a little more specific:
-
auto &guarantees that you are sharing the variable with something else. It is always a reference and never to a temporary. -
auto const &is likeauto &&, but provides read-only access.
What about for primitive/non-primitive types?
There is no difference.
Does this also apply to range based for loops?
Yes. Applying the above principles,
- Use
auto &&for the ability to modify and discard values of the sequence within the loop. (That is, unless the container provides a read-only view, such asstd::initializer_list, in which case it will be effectively anauto const &.) - Use
auto &to modify the values of the sequence in a meaningful way. - Use
auto const &for read-only access. - Use
autoto work with (modifiable) copies.
You also mention auto const with no reference. This works, but it’s not very commonly used because there is seldom an advantage to read-only access to something that you already own.