C + + 11 decltype (network collation)

decltype introduction

The emergence of type derivation at compile time is just for generic programming. In non generic programming, our types are determined and there is no need to deduce at all.

For compile time type derivation, in addition to the auto keyword we mentioned, there is also decltype in this paper.

Decltype, like the auto keyword, is used for compile time type derivation, but it is still different from auto. The type derivation of decltype does not obtain the type of variable from the initialization expression declared by the variable like auto, but always takes an ordinary expression as a parameter to return the type of the expression, and decltype does not evaluate the expression.

decltype usage

Derived expression type

    int i = 4;
    decltype(i) a; //The derivation result is int. The type of a is int.

Used with using/typedef to define types.

    using size_t = decltype(sizeof(0));//The return value of sizeof(a) is size_t type
    using ptrdiff_t = decltype((int*)0 - (int*)0);
    using nullptr_t = decltype(nullptr);
    vector<int >vec;
    typedef decltype(vec.begin()) vectype;
    for (vectype i = vec.begin; i != vec.end(); i++)
    {
        //...
    }

Like auto, this also improves the readability of the code.

Reuse anonymous types

In C + +, we sometimes encounter some anonymous types, such as:

struct 
{
    int d ;
    doubel b;
}anon_s;

With decltype, we can reuse this anonymous structure:

decltype(anon_s) as ;//Defines an anonymous structure above

Generic programming, combined with auto, is used to track the return value type of a function

This is also the biggest use of decltype.

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
    return x*y;
}

decltype derivation four rules

  1. If e is a marker expression without parentheses or a class member access expression, the decltype (E) of is the type of the entity named by E. In addition, if e is an overloaded function, it will cause compilation errors.
  2. Otherwise, assume that the type of E is T. if e is a dead value, decltype (E) is T&&
  3. Otherwise, assume that the type of E is T. if e is an lvalue, decltype (E) is T&.
  4. Otherwise, assuming that the type of e is T, decltype (e) is T.

Tags refer to the tags defined by the programmer except for the tags required by the compiler such as keywords and literals, and the expression corresponding to a single tag is the tag expression. For example:

int arr[4]

Then arr is a marker expression, and arr[3]+0 is not.

Let's look at the following code:

    int i=10;
    decltype(i) a; //a is derived as int
    decltype((i))b=i;//b is derived as int &, which must be initialized, otherwise compilation error

Just adding () to i leads to the difference of type derivation results. This is because i is a marker expression. According to derivation rule 1, the type is deduced as int. And (i) is an lvalue expression, so the type is deduced as int&.

The following code can further understand the derivation of the four rules

    int i = 4;
    int arr[5] = { 0 };
    int *ptr = arr;
    struct S{ double d; }s ;
    void Overloaded(int);
    void Overloaded(char);//Overloaded function
    int && RvalRef();
    const bool Func(int);
 
    //Rule 1: derivation as its type
    decltype (arr) var1; //int marker expression
 
    decltype (ptr) var2;//int * marker expression
 
    decltype(s.d) var3;//Double member access expression
 
    //decltype(Overloaded) var4;// Overloaded functions. Compilation error.
 
    //Rule 2: lose value. Derived as an R-value reference of type.
 
    decltype (RvalRef()) var5 = 1;
 
    //Rule 3: lvalues are derived as references to types.
 
    decltype ((i))var6 = i;     //int&
 
    decltype (true ? i : i) var7 = i; //Int & the conditional expression returns an lvalue.
 
    decltype (++i) var8 = i; //Int & + i returns the lvalue of i.
 
    decltype(arr[5]) var9 = i;//int&.  [] operation returns lvalue
 
    decltype(*ptr)var10 = i;//Int & * operation returns lvalue
 
    decltype("hello")var11 = "hello"; //Const char (&) [9] string literal constant is lvalue and const lvalue.

 
    //Rule 4: if none of the above is true, it is deduced as this type
 
    decltype(1) var12;//const int
 
    decltype(Func(1)) var13=true;//const bool
 
    decltype(i++) var14 = i;//int i + + returns the right value

It should be noted here that the string literal constant is an lvalue and const lvalue, while the non string literal constant is an lvalue.
So many rules are hard for us to remember, especially rule 3. We can use the template class is added in the C++11 standard library_ lvalue_ Reference to determine whether the expression is an lvalue:

    cout << is_lvalue_reference<decltype(++i)>::value << endl;

The result 1 is expressed as a left value, and the result 0 is a non right value.
Similarly, there is also is_rvalue_reference to determine whether the decltype inference result is an R-value.

Keywords: C++11

Added by greyhoundcode on Mon, 17 Jan 2022 19:00:22 +0200