C++ is a statically-typed language, that is, you must explicitly declare the type of every object before use. The type of an object specifies
- The amount of memory occupied
- How the memory (bits) is interpreted
- The operations allowable on the object
An object’s type is fixed at declaration – unless the programmer chooses to circumvent the type system using a cast.
Often for C++ objects specifying the type can be onerous:
C++11 allows automatic type-deduction to simplify the creation and maintenance of code.
The auto keyword has been appropriated from C (where it was a storage specifier indicating a local – ‘automatic’ – variable) that is almost never used. From C++11 onwards auto now means ‘deduce the type of an object’
Let’s start with some simple (but not particularly useful) examples.
The compiler uses the type of the initialiser to establish the type of the new object. Note, the object still has a definitive (and fixed) type. Type-deduction does not lead to ‘duck typing’.
(As an aside, one might reasonably argue that there is very little benefit in auto-deducing built-in types; and, in fact, could even be less explicit to the reader)
To use auto the compiler must have the information to deduce the type (and therefore allocate memory). Therefore, there are some (obvious?) limitations to where auto can be used:
The mechanism used by the compiler for type-deduction is the same one used to deduce parameter types for template functions. Because of this, the object-type deduced for an auto object may not be exactly what the programmer expects.
The rules are as follows:
- The deduced type will be a new object.
- If the initialiser is a reference-to-object, the reference is ignored (since a reference is just an alias for an object).
- Any const-volatile (cv)-qualifiers on the initialiser are ignored (since the cv-qualifiers are a property of the initialiser, not the new object).
- Arrays are degenerated into pointer types.
We can cv-qualify the deduced type separately, if required. The cv-qualifiers are applied to the new object – after its type has been deduced.
If we reference-qualify the auto-deduced type the rules change:
- The deduced type will now be a reference the initialiser object.
- Any cv-qualifiers of the initialiser will be maintained on the deduced type (since a reference cannot be less restrictive than its referent; although it can be more restrictive).
- If the initialiser is an array the deduced type is a reference-to-array type, not a pointer.
Returning to our original example, we can simplify the code (considerably) with the use of auto.
Additionally, the use of auto allows us a degree of flexibility in our code for future modifications:
More information
Can’t wait? Download the full set of articles as a PDF, here.
To learn more about Feabhas’ Modern C++ training courses, click here.
- Practice makes perfect, part 3 – Idiomatic kata - February 27, 2020
- Practice makes perfect, part 2– foundation kata - February 13, 2020
- Practice makes perfect, part 1 – Code kata - January 30, 2020
Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.
He specialises in C++, UML, software modelling, Systems Engineering and process development.
“C++ is a strongly-typed language, that is, you must explicitly declare the type of every object before use.”
That's not really what most people mean by “strongly typed”. F# and Haskell are even more strongly typed, but you don't need to declare the type of all variables due to type inference. I would rather say that (classical) C++ is *explicitly* typed.
Bonjour,
I guess it could be useful to say a word about usage of auto in the range for loop. For example :
1 - for (auto x : myVector) {...}
2 - for (auto &x : myVector) {...}
3 - for (const auto &x : myVector) {...}
Best regards, Philippe
Oh yes - but that's coming in another article, later 🙂
Agreed. It's a typo; I meant to say 'statically typed'. I've edited the article appropriately.
Thanks for the fix!
To be somewhat pedantic: To be statically typed does not mean that I you need to declare the types of all variables – just that the type checking happens at compile time. To use the same examples as above: F# and Haskell are statically typed, but you don't need to declare the types of all variables (their types can be inferred from how they're used). 🙂
Really helpful and amazing tips. Thanks