C++14: Return Type Deduction for Normal Functions

Written by on April 8, 2016 in C++, Programming with 0 Comments

In C++11, a function must specify its return type in one of the following two ways:

int aFunction(int arg) {

    return arg * 2;

}

(or)

auto aFunction(int arg) -> int {

    return arg * 2;

}

The first is the classic function definition syntax. The second form was introduced in C++11, and is useful if, for example, the return type depends on the argument types. This situation arises sometimes in the case of template functions:

template<typename T1, typename T2>

auto aTemplateFunction(T1 arg1, T1 arg2, T2 arg3) -> decltype(arg2 * arg3) {

    return arg2 * (arg3 – 1);

}

Here the decltype specifier comes in handy to determine the type of the return expression.

In C++14, the compiler is supposed to deduce the return type automatically, so the following is acceptable:

auto aFunction(int arg) {

    return arg * 2;

}

and even this:

template<typename T1, typename T2>

auto aTemplateFunction(T1 arg1, T1 arg2, T2 arg3)  {

    return arg2 * arg3 + 8;

}

The requirement is that the return value must be of the same type along every return path in the function body.

The following will trigger compilation error:

auto badFunction(int arg) {

    if (arg > 0)

        return arg; // ‘int’ return type

    return arg * 1.2; // ‘double’

}

This automatic return type deduction will work for recursive functions too, as long as there is a return preceding the recursive call.

// Precondition: N >= 0

auto factorial(int N)

{

    if(N == 0 || N == 1)

        return 1;

    return N * factorial (N – 1);

}

The above works as expected, but the following is not valid:

// Precondition: N >= 0

auto factorial2(int N)

{

    if(N > 1)

        return N * factorial2 (N – 1); // No previous return to deduce type

    return 1;

}

This automatic return type deduction feature is quite useful for the following reasons:

1) In many cases, we will have to type less (compared to the actual return type)!

2) During development phase, we tend to refactor the code, possibly resulting in different return types at different times. With auto, we need not worry about keeping the return type declaration in sync with what is actually returned. The compiler does it for us.

3) Some return types can be pretty verbose (without proper typedef). Using auto promotes readability in such cases. A simple example is pointer to functions.

4) What if the returned value is a lambda, or worse still, a function that returns a lambda (and so on…)? Let the compiler figure it out!

auto getLambda(int delta) {

    return [=](int arg) {return arg + delta;};

}

auto getFunctionThatReturnsLambda() {

    return getLambda;

}

Compare the above to what we would have to do in case auto was not allowed for the return type:

std::function<int(int)>

getLambda(int delta) {

    return [=](int arg) {return arg + delta;};

}

std::function<std::function<int(int)>(int)>

getFunctionThatReturnsLambda() {

    return getLambda;

}

Here we use the std::function<> template defined in <functional> STL header. Obviously, auto makes things much easier.

Overall, the auto return type specification introduced in C++14 is a very useful feature, something that every C++ programmer would use everyday. With Visual Studio 2015 Update 2 adding support for C++14, Windows programmers will be a happy lot!

Tags: ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published.

Top