C++11 auto and Boost.Auto
Consider how you declare an iterator to a vector of strings:
std::vector<std::string> names;
std::vector<std::string>::iterator iter = vec.begin();
The declared type of iter
is big and unwieldy and it is a pain to write it explicitly every time. Given that the compiler knows the type of the initializing expression on the right-hand side, that is, vec.begin()
, this is also superfluous. Starting with C++11, you can use the auto
keyword to ask the compiler to deduce the type of a declared variable using the type of the expression it is initialized with. Thus, the preceding tedium is replaced by the following:
std::vector<std::string> names;
auto iter = vec.begin();
Consider the following statement:
auto var = expr;
The deduced type of var
is the same as the deduced type T
, when the following function template is called with the argument expr
:
template <typename T> void foo(T); foo(expr);
Type deduction rules
There are a few rules to keep in mind. First, if the initializing expression is a reference, the reference is stripped in the deduced type:
int x = 5;
int& y = x;
auto z = y; // deduced type of z is int, not int&
If you want to declare an lvalue-reference, you must explicitly adorn the auto
keyword with an ampersand (&), as shown here:
int x = 5;
auto& y = x; // deduced type of y is int&
If the initializing expression is not copyable, you must make the assignee a reference in this way.
The second rule is that const
and volatile
qualifiers of the initializing expression are stripped in the deduced type, unless the variable declared with auto
is explicitly declared as a reference:
int constx = 5; auto y = x; // deduced type of y is int auto& z = x; // deduced type of z is constint
Again, if you want to add a const
or volatile
qualifier, you must do so explicitly, as shown:
intconst x = 5;
auto const y = x; // deduced type of y is constint
Common uses
The auto
keyword is very convenient to use in a lot of situations. It lets you get away from having to type long template IDs, in particular when the initializing expression is a function call. Here are a couple of examples to illustrate the advantages:
auto strptr = boost::make_shared<std::string>("Hello"); // type of strptr is boost::shared_ptr<std::string> auto coords(boost::make_tuple(1.0, 2.0, 3.0)); // type of coords is boost::tuple<double, double, double>
Note the savings in the type names achieved through the use of auto
. Also, note that while creating the tuple
called coords
using boost::make_tuple
, we do not use the assignment syntax for initialization.
Boost.Auto
If you are on a pre-C++11 compiler, you can emulate this effect using the BOOST_AUTO
and BOOST_AUTO_TPL
macros. Thus, you can write the last snippet as follows:
#include <boost/typeof/typeof.hpp> BOOST_AUTO(strptr, boost::make_shared<std::string>("Hello")); // type of strptr is boost::shared_ptr<std::string> BOOST_AUTO(coords, boost::make_tuple(1.0, 2.0, 3.0)); // type of coords is boost::tuple<double, double, double>
Note the header file boost/typeof/typeof.hpp
that needs to be included to use the macro.
If you want to declare a reference type, you can adorn the variable with a leading ampersand (&). Likewise, to qualify your variable with const
or volatile
, you should add the const
or volatile
qualifier before the variable name. Here is an example:
BOOST_AUTO(const& strptr, boost::make_shared<std::string>("Hello"));
// type of strptr is boost::shared_ptr<std::string>