2.5.2 The auto Type Specifier
It is not uncommon to want to store the value of an expression in a variable. To declare the variable, we have to know the type of that expression. When we write a program, it can be surprisingly difficult—and sometimes even impossible—to determine the type of an expression. Under the new standard, we can let the compiler figure out the type for us by using the auto type specifier. Unlike type specifiers, such as double, that name a specific type, auto tells the compiler to deduce the type from the initializer. By implication, a variable that uses auto as its type specifier must have an initializer:
-
- auto item = val1 + val2;
Here the compiler will deduce the type of item from the type returned by applying + to val1 and val2. If val1 and val2 are Sales_item objects (§ 1.5, p. 19), item will have type Sales_item. If those variables are type double, then item has type double, and so on.
As with any other type specifier, we can define multiple variables using auto. Because a declaration can involve only a single base type, the initializers for all the variables in the declaration must have types that are consistent with each other:
- auto i = 0, *p = &i;
- auto sz = 0, pi = 3.14;
Compound Types, const, and auto
The type that the compiler infers for auto is not always exactly the same as the initializer’s type. Instead, the compiler adjusts the type to conform to normal initialization rules.
First, as we’ve seen, when we use a reference, we are really using the object to which the reference refers. In particular, when we use a reference as an initializer, the initializer is the corresponding object. The compiler uses that object’s type for auto’s type deduction:
- int i = 0, &r = i;
- auto a = r;
Second, auto ordinarily ignores top-level consts (§ 2.4.3, p. 63). As usual in initializations, low-level consts, such as when an initializer is a pointer to const, are kept:
- const int ci = i, &cr = ci;
- auto b = ci;
- auto c = cr;
- auto d = &i;
- auto e = &ci;
If we want the deduced type to have a top-level const, we must say so explicitly:
- const auto f = ci;
We can also specify that we want a reference to the auto-deduced type. Normal initialization rules still apply:
- auto &g = ci;
- auto &h = 42;
- const auto &j = 42;
When we ask for a reference to an auto-deduced type, top-level consts in the initializer are not ignored. As usual, consts are not top-level when we bind a reference to an initializer.
When we define several variables in the same statement, it is important to remember that a reference or pointer is part of a particular declarator and not part of the base type for the declaration. As usual, the initializers must provide consistent auto-deduced types:
- auto k = ci, &l = i;
- auto &m = ci, *p = &ci;
-
- auto &n = i, *p2 = &ci;
EXERCISES SECTION 2.5.2
Exercise 2.33: Using the variable definitions from this section, determine what happens in each of these assignments:
a = 42; b = 42; c = 42;
d = 42; e = 42; g = 42;
Exercise 2.34: Write a program containing the variables and assignments from the previous exercise. Print the variables before and after the assignments to check whether your predictions in the previous exercisewere correct. If not, study the examples until you can convince yourself you know what led you to the wrong conclusion.
Exercise 2.35: Determine the types deduced in each of the following definitions. Once you’ve figured out the types, write a program to see whether you were correct.
- const int i = 42;
- auto j = i; const auto &k = i; auto *p = &i;
- const auto j2 = i, &k2 = i;