Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

auto for the People

Last updated Jan 1, 2003.

The auto and decltype proposal introduces three new features to C++09. The revived keyword auto is used for deducing the type of an object from its initializer. A new operator called decltype retrieves the type of an expression or value. Finally, new function declaration syntax allows you to deduce the return type of a function from an expression.  

auto in K&R C

Historically, the auto keyword was a storage type specifier indicating an object that has automatic storage type (i.e. allocated on the stack).  You never really have to use the keyword auto to indicate automatic storage type because this storage type is the default type of objects declared inside a function or a block. auto was useful in K&R C in corner cases such as this one:

void func() 
{
auto myvar; //implicit int
}

The "default to int" rule allowed the programmer to omit an explicit type name when the object in question was supposed to be of type int. For example:

//pre C99 code
static var=0;
const x=100; 

The default to int rule was removed from C++ about 15 years ago. It was subsequently removed from C99 as well. As a result, auto became a completely redundant keyword in both C and C++. Recently, the C++ standard committee removed the auto storage type specifier from C++09.  The auto keyword itself wasn't removed from the language though. Instead, it was assigned an entirely new role. 

auto in C++09

Examine the following valid C++ declarations:

const int MAX=1024;
double factor=1.6666667;
const static char error_message[]="unit failure";
bool initialized=false;

They're verbose and contain redundant information. The initializers already convey the variable's type implicitly. For example, the literal 1024 is int, 1.6666667 is double etc.  Why spell out the type in the declaration explicitly? With auto, you can declare variables without their type names. auto automatically deduces the type of an object from its initializer:

auto factor=1.6666667; //factor is double
const auto error_message[]="unit failure"; // const char[14] 
auto initialized=false; // bool
auto s=string("test"); //string

In declarations that involve qualified names and complex template specializations, auto simplifies complex code. Consider the following for-loop:

std::vector <int> vi;
for (std::vector<int>::iterator it= vi.begin(); it<vi.end(); ++it)
{
//... 
}

With auto the declaration of the iterator is reduced to:

for (auto it= vi.begin();it<vi.end(); ++it)

auto also deduced the type from a function call initializer:

int func();
vector<double> foo();
auto x1=func();//x1 is int
auto vd=foo(); //vector<double>

Reference Types, CV qualifiers and Storage Specifiers

How are references handled? At the Lillehammer and Mont Tremblant meetings, committee members pointed out the potential difficulty of figuring out whether the declared variable is a reference type in cases such as these:

struct B { virtual void f();}
struct D: B{};
B * dp= new D;
auto b = *dp; //casting a reference to a base or slicing a value object?
b.f(); // is the call polymorphic?

Basing auto on the template deduction rules resolves this ambiguity and enables programmers to express their intentions intuitively. To declare a reference, use auto& instead of auto. Similarly, use const auto, volatile auto,  auto*  and static auto in an auto declaration:

int & func();
int* g();
auto x=func(); //x is int
auto& y=func(); //y is int&
const auto & z=func(); //const int&
auto * p=g(); // int* 
static auto z=0.5; //static double

Multi-Variable Declarations

According to the revised proposal, a single auto statement can now declare multiple variables:

auto n=5, *pi=&n, const z=Foo();

This statement first declares n whose type is int, a variable pi whose type is int* and a third variable z whose type is const Foo. Notice that declarations of multiple variables require a left to right parsing order because the leftmost variable's type must be deduced before any other variable's type. Obviously, the variable being declared cannot be used as its own initializer:

auto n=&n; //error

Direct Initialization Syntax

auto supports direct initialization syntax in the form of T v(x) too:

auto a=1;  
auto a(1); //same meaning as above

Direct initialization syntax can be used in a new expression:

new auto(10); 

The expression auto(10) is int. The entire new expression therefore has the type int *. Using the new expression as the initializer of an auto variable is also allowed:

auto y=new auto(10); //y is int*

decltype

C++09 has a new operator called decltype. An expression delctype(e) evaluates as the type of the expression e:

int n;
decltype(n); //int
bool func();
decltype(&func); // bool(*)(void)
decltype(func()); // bool 
char c[10];
decltype(c); // char[10]

What about reference types? In other words:

int &ref=n;
decltype(ref) //int or int&?

Similarly, what about const and volatile qualifiers? According to the latest version of the proposal, these are all preserved (as opposed to the auto type deduction rules):

int a;
int &b=a;
const int &ci=a;
const int d=10;
const Foo e;
decltype(a); //int
decltype(b); //int&
decltype(c); const int&

decltype(d); //const int
decltype(e); //const Foo

Similarly, formal function parameters and function types preserve their types:

void f(int a, int& b, const int &c, int* d)
{
 decltype (a); //int
 decltype (b); //int&
 decltype (c); //const int&
 decltype (d); //int *
}
//function types
int f(bool);
decltype(f); // int (bool)
decltype(&f); //int (*) (bool)
decltype(*&f); //int (&) (bool)

Arrays and class members are handled similarly:

int x[10];
declytpe (x); //int[10]
class A
{
 int a;
 int & b;
 int func(int);
 int & g() const;
};
decltype(&A::a); //int A::*
decltype(&A::b); //error, pointers to reference members are prohibited in the standard
decltype(&A::func);//int (A::*) (int)
decltype(&A::g);//int& (A::*) () const

New Function Declaration Syntax

Function declarations have a new syntactic form that takes advantage of auto and decltype.

auto func(int x)-> double;

func() has a return type double. Notice that the return type of auto function is placed after the closing parenthesis of the parameter list. The return type is indicated by an ->. By combining auto and decltype the return type of the function can be deduced from an expression or a value:

auto g(double d)-> decltype(d); //return type is double

Template functions can use the new function declaration syntax to deduce their return type automatically from their return statement:

template <class T>
auto get_end(vector<T>& v) {return v.end()) ->decltype(v.end()); //return type is vector<T>::iterator
template <class T>
auto get_end(const vector<T>& v) {return v.end()) ->decltype(v.end()); //return type is vector<T>::const_iterator