Automatic Type Inference

One of the nice new features introduced by C++0x is automatic type inference for declarations. Essentially, it means that the compiler will figure out the declaration type based on information from the right-hand side of the expression. If you come from C#, then this is something you’ve already seen with “var” declarations. In C++, you use the “auto” keyword for this.

auto i = 12;  // i is an integer
auto c = "Hello world"; // c is a const char *

My examples are considerably contrived, as you don’t really gain that much by using the auto keyword instead of an explicit type declaration. However, automatic type inference certainly has its place. Here’s an example that STL programmers are likely all too familiar with:

// My fingers hurt after typing this
for (std::map< std::string, std::vector< std::string > >::iterator iter = myMap.begin(); iter != myMap.end(); ++iter) {

You would generally work around the verbosity by using a typedef. This also had the extra benefit of allowing you to change containers later without having to change each usage of it. So now the code would look like:

// A bit better for the fingers
typedef std::map< std::string, std::vector< std::string > > MyMap;
for (MyMap::iterator iter = myMap.begin(); iter != myMap.end(); ++iter) {

However, you no longer have to do the typedef’s manually — you can let the compiler handle the magic for you, while still retaining the benefits of changing container types seamlessly later on.

// Tada!
for (auto iter = myMap.begin(); iter != myMap.end(); ++iter) {

If you’re still not convinced that the auto keyword is a useful language feature, then there’s one more case you should consider before passing final judgement. Another new language feature of C++0x is lambda expressions. Without going into too much detail about lambdas, you can consider them as being function objects. Being objects, they are usable on the right-hand side of an expression, so you can assign them to variables. But you need a way to express them as a type, and that’s where the auto keyword comes into play. Lambda expressions have a distinct type, and they are type safe, and you need to use the auto keyword if you wish to assign them to a variable for use later.

auto min = [&](int a, int b) { return (a < b) ? a : b; };
std::sort( myVector.begin(), myVector.end(), min );

So now that you can see what the auto keyword can do, what can’t it do? Well, you can’t use auto for declaring variables without a right-hand side expression (so you can’t just say auto i; and be done with it). You also can’t declare parameters of type auto, nor return values. Effectively, this is only for variable declarations where the type can be deduced as part of the declaration itself.

As a historical aside, this isn’t the first time we’ve seen the “auto” keyword in C and C++. It’s actually a storage class specifier, like static and extern. In ancient times, you would use the auto keyword to tell the compiler that the variable has automatic storage. Considering that automatic storage was also the default behavior of any variable declaration, you didn’t usually see this keyword used..well..ever. Being the language masochist that I am, I checked to see if you could declare a type-inferred variable with automatic storage and the answer is: no, because there is no more automatic storage specifier in C++0x. But you can declare a type-inferred value with other storage class specifiers such as static or register.

tl;dr: you can use the auto keyword when declaring variables to skip figuring out the type yourself.

This entry was posted in C/C++ and tagged , . Bookmark the permalink.

3 Responses to Automatic Type Inference

  1. Rajendra says:

    In addition to what auto can’t do, it cannot be used for defining arrays. For example:
    auto A[3] = {1, 2, 3}; // Error

    Aaron – Can you tell why this might have been disallowed?

  2. Rajendra says:

    Aaron – I’m liking your posts specifically on C++0x. Care to include a post on right-angled brackets restriction removal for double template parameter declaration?

  3. Aaron Ballman says:

    @Rajendra — I’m glad you’re liking the C++0x posts! There’s really not too much to say on the right angle bracket front. The specification simply became more aligned with how most compilers already treated them. It was just one of those language extensions that was so ubiquitous that it became standard.

    As for auto and arrays, that’s a very good question! I believe you are able to define arrays in that fashion, after a sort. Part of the problem boils down to how auto works and how initializer lists work. As far as I understand it (which is limited since I’ve not looked into initializer lists too deeply yet), that initializer list will become a std::initializer_list< int >, and the compiler doesn’t have the logic to turn that into an array. I think I’ll have to do some more research on the subject though, so don’t give my guess too much weight.

Leave a Reply

Your email address will not be published. Required fields are marked *