Use of decltype keyword of new features of C++11

Posted by timelf123 on Sat, 08 Jan 2022 11:11:31 +0100

I decltype keyword introduction

Decltype keyword is similar to auto keyword, but there are differences; The auto keyword determines the type represented by auto through the initialized variables at compile time. In other words, the expression modified by auto must be an initialized variable; So what if we just want to get the type of this variable? At this time, it's decltype's turn. The decltype keyword is also used to derive the type of an expression during compilation, but whether the expression is initialized or not has little impact on the compiler.

The following is an example of using the decltype keyword:

#include <iostream>
using namespace std;

int main()
{
    int x = 0;
    decltype(x) y = 1;  //y -> int
    cout << y << endl;
    decltype(x + y) z = 2; //z -> int
    cout << z << endl;

    const int& i = x;
    decltype(i) j = y;  //j -> const int &

    cout << j << endl;

    const decltype(z) *p = &z;  //*p -> const int
    decltype(z) *pi = &z;       //*pi -> int, pi->int*
    decltype(pi) *pp = &pi;     //*pp -> int*, pp->int**

    cout << pp << endl;         //Print result: 0x61fe80
    cout << *pp << endl;        //Print result: 0x61fe84
    cout << **pp << endl;       //Print result: 2

    return 0;
}

A. The results of Y and z show that decltype can directly deduce the type of variable according to the expression. This function is very similar to that of auto, but different. Auto can only deduce the type of variable according to the initialization expression of variable. If you want to get the type through an expression, but you don't want the new variable to have the same value as this expression, Then auto is not applicable at this time.

B. The results of J show that decltype can retain the reference and const qualifier of the expression. Decltype can accurately deduce the type of the expression definition itself, and will not abandon the reference and cv qualifier in some cases like auto.

C. The results of P and pi show that decltype can add references, pointers and cv qualifiers like auto.

D. The derivation of pp shows that when the expression is a pointer, decltype can still deduce the actual type of the expression (pointer type). Then, combined with the pointer mark when pp is defined, the obtained pp is a two-dimensional pointer type

II Derivation rules of decltype

The derivation rules of decltyp(exp) are as follows:

(1). Identifier expressions and class access expressions.

(2). Function call (neither identifier expression nor class access expression).

(3). Bracketed expressions and addition expressions (other cases).

Let's start with the first case:

#include <iostream>
using namespace std;

class Test
{
public:
    Test() {}

public:
    static const int nNumber = 0;
    int x;
};

int main()
{

    //Class access expression
    decltype(Test::nNumber) c = 10;
    Test test;
    decltype(test.x) d = 20;
    cout << c << "," << d <<endl;

    //Identifier expression
    int y = 20;
    decltype(y) z = 30;
   return 0;
}

The second case: function call

#include <iostream>

using namespace std;

class Test
{
public:
    Test() {}

public:
    int m_nNum = -10;
};

int Test_Int();             //Pure right value
int& Test_Int_One();        //Lvalue

const int Test_Cint();      //Pure right value
const int& Test_Cint_One(); //Lvalue

const Test Test_Class();    //Pure right value

int main()
{
    int x = 10;

    decltype(Test_Int()) a1 = x;        //a1->int
    cout << a1 << endl;

    decltype(Test_Cint_One()) a2 = x;   //a2->int&
    int y = a2;
    cout << y << endl;
    cout << a2 << endl;

    decltype(Test_Cint()) b1 = x;       //b1->const int
    b1 = 20;
    cout << b1 << endl;

    decltype(Test_Cint_One()) b2 = x;   //b2->const& int
    //b2 = 30;                            //error:b2 is only a read-only reference and cannot be assigned a value
    cout << b2 << endl;

    decltype(Test_Class()) c1 = Test();
    cout << c1.m_nNum << endl;

    return 0;
}

It can be seen that the result of deriving decltype according to rule 2 is consistent with the return value type of the function, but it should be noted that b1 is int rather than const int, because the int returned by the function is a pure right value. For pure right values, only class types can carry the cv qualifier, and other types generally ignore the cv qualifier; Therefore, b1 derived from decltype is an int type, while the type derived from c1 is const Test.

The third kind: bracketed expression and addition expression

#include <iostream>

using namespace std;

class Test
{
public:
    Test() {}

public:
    static const int nNum = -10;
    int x = 0;
};


int main()
{
    const Test test = Test();

    decltype(test.x) a = 0;     //a->int
    decltype((test.x)) b = a;   //b->const int&
    b = 10;                     //error:b is a read-only reference
    cout << b << endl;

    int m =0,n=0;
    decltype(m + n) c = 10;     //c->int
    decltype(m += n) d = c;      //d ->int &


    return 0;
}

Results of a and b: only a pair of additional parentheses are added, but the types they get are not the same.

The result of a is obvious. According to derivation rule 1, the type of a is test Definition type of X.

The results of b do not apply to derivation rule 1 and derivation rule 2 according to test X is an lvalue, so the bracket expression is also an lvalue. Therefore, according to derivation rule 3, we can know that the result of decltype will be an lvalue reference; Because test is defined as const Test, foo X is an lvalue of const int type, so the derivation result of decltype is const int &

Similarly, m+n returns an R-value, and the result of decltype is int. Finally, m+=n returns an lvalue. According to derivation rule 3, the result of decltype is int &

Topics: C++