Improved Type Reference in C++11: auto, decltype, and the new function declaration syntax

Home / Improved Type Reference in C++11: auto, decltype, and the new function declaration syntax

C++11 introduces several new type inference capabilities. It mean you can spend less time having to write out things the compiler already knows. Of course there are times when you need to help out the compiler or your fellow programmers. But with C++11, you can spend less time on the mundane stuff and focus on the logic.

Let’s start by looking at the most immediately obvious new benefit, the auto keyword

The joy of auto

In C++11, the compiler can infer the type of a variable at the point of declaration. So, instead of putting in the variable type, you can just write auto:

long x = 4L;

can now be replaced with

auto x = 4L;

This is look simple. But the most benefit would be when we use templates and iterators:

vector<int> vec;
auto itr = vec.iterator(); // instead of vector<int>::iterator itr

There are other times where auto comes in handy, too. For example, let’s say that you had some code of the form:

template <typename BuiltType, typename Builder>
makeAndProcessObject (const Builder& builder)
    BuiltType val = builder.makeObject();
    // do stuff with val

In this code, you can see that there are two necessary template parameters–one for the type of the “builder” object, and a second for the type of the object being built. Even worse, the type of the built object cannot be deduced by the template parameter. Every call must look like this:

MyObjBuilder builder;
makeAndProcessObject<MyObj>( builder );

But auto immediately reduces this ugliness to nothing because we no longer need to be able to write the specific type at the point where you build the object. We can let C++ deduce it for us:

template <typename Builder>
makeAndProcessObject (const Builder& builder)
    auto val = builder.makeObject();
    // do stuff with val

Now we only need a single template parameter, and that parameter is easily inferred when calling the function:

MyObjBuilder builder;
makeAndProcessObject( builder );

This is way better for the caller, and the template code loses nothing in readability–if anything, it’s easier to understand!

Decltype and the new return value syntax

Now you might be saying here — okay, that’s great, but what if I wanted to *return* the value that this builder object created? I still need to provide the template argument becuase I need to provide the return type. Well, it turns out that the standards committee is full of smart people, and they have an extremely nice solution to this problem. It comes in two parts: decltype and the new return value syntax.

New Return Value Syntax

Let’s start off with the new, optional, return value syntax, since it manages to find yet another use for auto. In all prior versions of C and C++, the return value of a function absolutely had to go before the function:

int multiply (int x, int y);

In C++11, we can now put the return value at the end of the function declaration, substituting auto for the name of the return type, if we want to:
auto multiply (int x, int y) -> int;
So would you want to do this? Let’s look at a simple example where it helps us: a class with an enum declared inside it:

class Person
    enum PersonType { ADULT, CHILD, SENIOR };
    void setPersonType (PersonType person_type);
    PersonType getPersonType ();
    PersonType _person_type;

Here we have a simple class, Person, that has a type: whether the person is an adult, a child, or a senior citizen. Not much special about it, but what happens when you go to define the methods?

The first method, the setter, is trivial to declare, you can use the enum type PersonType without any trouble:

void Person::setPersonType (PersonType person_type)
    _person_type = person_type;

On the other hand, the second method is a bit of a mess. The nice clean looking code won’t compile:

// the compiler doesn't know what PersonType is because PersonType 
// is being used outside of the Person class
PersonType Person::getPersonType ()
    return _person_type;

We have to write:

Person::PersonType Person::getPersonType ()
    return _person_type;

to make the return value work correctly. This isn’t that big of a deal, but it’s pretty easy to do by mistake, and it can get much messier when templates are involved.

This is where the new return value syntax comes in. Because the return value goes at the end of the function, instead of before it, you don’t need to add the class scope. By the point the compiler reaches the return value, it already knows the function is part of the Person class, so it knows what PersonType is.

auto Person::getPersonType () -> PersonType
    return _person_type;

Okay, while that’s very nice, does it really help us out? We can’t use this new syntax to solve the problem we had before, can we? Well, not yet. Let’s add one more concept: decltype


Decltype is auto’s not-evil twin. Auto lets you declare a variable with a particular type; decltype lets you extract the type from a variable (or any other expression).

int x = 3;
decltype(x) y = x; // same thing as auto y = x;

You can use decltype for pretty much any expression, including to express the type for a return value from a method. Hmm, that sounds like a familiar problem doesn’t it? What if we could write:

decltype( builder.makeObject() )

This would give us the type that is returned from makeObject, allowing us to specify the return value from makeAndProcessObject. We can combine this with the new return value syntax to produce this method:

template <typename Builder>
makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )
    auto val = builder.makeObject();
    // do stuff with val
    return val;

This only works with the new return value syntax because under the old syntax, we couldn’t refer to the function argument, builder, at the point where we declare the return type. With the new syntax, all of the arguments to a function are fair game!

Auto, References, Pointers and Const

One question that is sure to come up is how auto handles references:

int& foo();

auto bar = foo(); // int& or int?

The short answer is in C++11, auto defaults to being by-value for references, so in the above code bar is an int. However, you can add the & as a modifier to force it to be a reference:

int& foo();

auto bar = foo(); // int
auto& baz = foo(); // int&

On the other hand, if you have a pointer auto will automatically pick up pointerness:

int* foo();

auto p_bar = foo(); // int*

But we can also (thankfully) be explicit about it, and indicate that the variable is a pointer:

int* foo();
auto *p_baz = foo(); // int*

You can similarly tack const onto auto if you need it, when dealing with references:
int& foo();

const auto& baz = foo(); // const int&

Or with pointers:

int* foo();
const int* const_foo();
const auto* p_bar = foo();   // const int*
auto p_bar = const_foo();    // const int*

Overall, it feels quite natural and normal, and it follows the normal type inference rules of templates in C++.

As this article written, GCC 4.4 and MSVC 10 both support everything we have discussed about in this article. To use C++11 feature on gcc, you can add -std=c++0x on your compiling command. Try to use GCC or using MSVC 10, and start using these techniques today. If you’re using another compiler, check out their page for details of C++11 compiler support.


, ,

About Author

about author


A man who is obsessed to low level technology.

  1. Guide to Lambda Closure in C++11 - Xathrya.ID

    […] it looks just like calling any other function. By the way, notice how easy this is to do with auto! You don’t need to sweat the ugly syntax of a function […]

  2. C++ Ranged Based Loop - Xathrya.ID

    […] to getting code written quickly. One example we’ve already covered is the new meaning of the auto keyword; now I’d like to talk more about the range-based for loop–both how to use it, and how […]

  3. Ten C++11 Features You Should Know and Use - Xathrya.ID

    […] More: Improved Typed Reference in C++11: auto, decltype, and new function declaration syntax […]

Leave a Reply

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

Social Share Buttons and Icons powered by Ultimatelysocial