- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- A Tour of C99
- C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The
shared_ptrClass - The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The constexpr Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: export, Exception Specification and register
- The Rejection of the Unified Function Syntax Proposal
- Rvalue References as Object Members
- FCD Approved
- The Debate on noexcept, Part I
- The Debate on noexcept, Part II
- The Debate on noexcept, Part III
- C++0x Concurrency
- The Reflecting Circle New
- We Have Mail New
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
auto for the People
Last updated May 23, 2008.
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


Account Sign In
View your cart