Short answer: More completely, my current opinion on auto
is that you should useauto
by default unless you explicitly want a conversion. (Slightly more precisely, "... unless you want to explicitly commit to a type, which nearly always is because you want a conversion.")
Longer answer and rationale:
Write an explicit type (rather than auto
) only when you really want to explicitly commit to a type, which nearly always means you want to explicitly get a conversion to that type. Off the top of my head, I recall two main cases:
- (Common) The
initializer_list
surprise thatauto x = { 1 };
deducesinitializer_list
. If you don’t wantinitializer_list
, say the type -- i.e., explicitly ask for a conversion. - (Rare) The expression templates case, such as that
auto x = matrix1 * matrix 2 + matrix3;
captures a helper or proxy type not meant to be visible to the programmer. In many cases, it's fine and benign to capture that type, but sometimes if you really want it to collapse and do the computation then say the type -- i.e., again explicitly ask for a conversion.
Routinely use auto
by default otherwise, because using auto
avoids pitfalls and makes your code more correct, more maintainable and robust, and more efficient. Roughly in order from most to least important, in the spirit of "write for clarity and correctness first":
- Correctness: Using
auto
guarantees you’ll get the right type. As the saying goes, if you repeat yourself (say the type redundantly), you can and will lie (get it wrong). Here's a usual example:void f( const vector<int>& v ) { for( /*…*
-- at this point, if you write the iterator’s type explicitly, you want to remember to writeconst_iterator
(did you?), whereasauto
just gets it right. - Maintainability and robustness: Using
auto
makes your code more robust in the face of change, because when the expression's type changes,auto
will continue to resolve to the correct type. If you instead commit to an explicit type, changing the expression's type will inject silent conversions when the new type converts to the old type, or needless build breaks when the new type still works-like the old type but doesn't convert to the old type (for example, when you change amap
to anunordered_map
, which is always fine if you aren't relying on order, usingauto
for your iterators you'll seamlessly switch frommap<>::iterator
tounordered_map<>::iterator
, but usingmap<>::iterator
everywhere explicitly means you'll be wasting your valuable time on a mechanical code fix ripple, unless an intern is walking by and you can foist off the boring work on them). - Performance: Because
auto
guarantees no implicit conversion will happen, it guarantees better performance by default. If instead you say the type, and it requires a conversion, you will often silently get a conversion whether you expected it or not. - Usability: Using
auto
is your only good option for hard-to-spell and unutterable types, such as lambdas and template helpers, short of resorting to repetitivedecltype
expressions or less-efficient indirections likestd::function
. - Convenience: And, yes,
auto
is less typing. I mention that last for completeness because it's a common reason to like it, but it's not the biggest reason to use it.
Hence: Prefer to say auto
by default. It offers so much simplicity and performance and clarity goodness that you're only hurting yourself (and your code's future maintainers) if you don't. Only commit to an explicit type when you really mean it, which nearly always means you want an explicit conversion.
Yes, there should be a GotW about this. This suffices for now. :)
Reference:
http://programmers.stackexchange.com/questions/180216/does-auto-make-c-code-harder-to-understand/