Pages

getteammates.com

Saturday, 5 March 2016

auto and decltype in C++11 and C++14

C++11 and C++14 compiler helps you to find out the type of a variable, function with the introduciton of auto. auto works similar to var in C#.

auto with declarations

So instead of declaring
    int x = 10;
you can declare
    auto x = 10; 

Can we use auto without initialization? No. In this case compiler will not be able to deduce the type of the variable.

Can we use auto with class member  variable? Only where you can initialize the member variable; static constants. So the below shown declaration is valid.
    class Test
    {
    public:
        static const auto x = 4;
    };

auto with functions

In C++11

Another place where we can use auto is with function return type. But there is a catch in using auto with return type. If you just use as shown below things will not work,
    auto add(int x, int y) {
        return x+y;
    }

You can definitely use auto in place of function return type, if you change the function to as shown below,
    auto add(int x, int y) -> int {
        return x+y;
    }

This doesn't look like too interesting, isn't it; it is just that we are specifying the return type in a different place. We will see some use of having auto with function declaration in c++11 in below sections

In C++14

In C++14 the first version of add function defined above will work fine.

What if we have multiple return statement with different types? you will get a compilation error. So the following function will give you compilation error.
auto factorial(int n) 
{
    if (n == 1) {
        return int(1);
    }
    if (n == 2) {
        return long(2);
    }

    int res = 1;
    for (; n>0; --n) {
        res *= n;
    }

    return res;
}

What about the following recursive function? 
auto factorial(int n) 
{
    if (n > 1) {
        return factorial(n-1) * n;
    }

    return 1;
}

Another compilation error. It is not allowed to call recursive function call before a return statement.
So change the function slightly as shown below and everything should start working.
auto factorial(int n) 
{
    if (n == 1) {
        return 1;
    }
    return factorial(n-1) * n;
}

In c++14 you can also make function parameter auto, the below given version of factorial works just fine in c++14.
auto factorial(auto n)
{
    if (n == 1) {
        return 1;
    }
    return factorial(n-1) * n;
}

decltype

Let me introduce another feature, decltype,  and see if the auto in function return type has any benefit or not.
decltype helps to get the type of a variable or expression, one use of it is shown below,
    float a = 1.0f;
    decltype(a) b = a;

Ok so we have got another way to declare variable. We can use auto as well in this case, what benefit does decltype brings?
Now lets go back the function that we declared and see if we can use decltype there, maybe we can. Modified function is shown below,
    auto add(int x, int y) -> decltype(x) {
        return x+y;
    }
Another interesting thing about decltype is that we can also give expression with it. The following code  snippet works really well and the return type will be float.
    auto add(float x, int y) -> decltype(x+y) {
        return x+y;
    }

Like sizeof operator the expression in decltype will not  be getting evaluated. So the following program will output 1,1.
    #include <iostream>

int main(int argc, char **argv) {
    int x = 1;
    decltype(++x) y = x;
    std::cout << x << "," << y<< std::endl;
}   

auto with reference

Now lets see how auto works with references, can you guess what is the output of the following code block?
#include <iostream>
    
int & incr(int &x)
{
    return ++x;
}

int main(int argc, char **argv) {
    int x = 1;
    auto y = incr(x);
    ++y;
    std::cout << x << std::endl;
}

It is 2 not 3. auto type by default takes the value not reference. Change the declaration as shown below and everything should work as expected.
    auto & y = incr(x);

Then what about pointers?auto works as expected, it is not necessary to specify as auto *

decltype(auto) - c++14

The above code can be made to work as expected using  decltype(auto), It takes the type from the initialization

#include <iostream>

int & incr(int &x)
{   
    return ++x;
}   

int main(int argc, char **argv) {
    int x = 1;
    decltype(auto) y = incr(x);
    ++y;
    std::cout << x << std::endl;
}  

Output of the above program is 3.

Now lets change the function incr function by using auto as shown below and lets see what happens.
#include <iostream>

auto incr(int &x)
{   
    return ++x;
}   

int main(int argc, char **argv) {
    int x = 1;
    decltype(auto) y = incr(x);
    ++y;
    std::cout << x << std::endl;
} 
Now the output is 2.

How do we fix this to make the behaviour same as that of the first program? One way is to use decltype(auto) with function as shown below,
#include <iostream>

decltype(auto) incr(int &x)
{   
    return ++x;
}   

int main(int argc, char **argv) {
    int x = 1;
    decltype(auto) y = incr(x);
    ++y;
    std::cout << x << std::endl;
}  

Please visit http://blog.trsquarelab.com/2015/05/compiling-c11-and-c14-programs-with-gcc.html for information on how to compile with C++11 and C++14 support in Ubuntu using GCC

No comments:

Post a Comment