@oBFusCATed
I don't want to derail this topic too much, this can lead to philosophical questions like tabs vs. space, but these range-based for loops are one of the best places to use auto imho, so i couldn't resist.
The key point is to write flexible, reusable code and to achieve that you don't "code against the type" but "code against the properties", and for this you don't need the concrete type. For example pointers, in most locations it doesn't matter if it's a raw pointer or a smart pointer (it only matters if you need to create or destroy it), you only need to know what you can do with it, like dereference.
Another example that touches point 1-3 is if you need to store the return value of a method. Something like that:
unsigned int index = getIndex(const Item& item);
Somewhere in your code this method is defined and in that place its return type is defined. Now in this line you again define its return type. You define the same thing in two places, bad if you need to change the definition of the method someday because you need to change all the others places as well. And does it really matter to see in that line that index is an unsigned int? What if it is a size_t? uint64_t? std::vector<Item>::size_type? It is an index, you can increment it, decrement it, compare it against some capacity value, thats what you need to know.
Actually this simple line is one of the reasons why i can't port a quite sized codebase to run in 32 Bit or 64 Bit, the method returns a size_type which changes from 32 Bit to 64 Bit but the unsigned int stays, depending on platform, 32 Bit. With auto i wouldn't need to take care of these places.