c++c++11decltype

What is decltype and how is it used?


I haven't been able to find a good explanation of decltype. Please tell me, as a beginning programmer, what it does and why it is useful.

For example, I am reading a book that asked the following question:

What would be the type of each variable and what value would each variable have when the code finishes?

int a = 3, b = 4;    
decltype(a) c = a;
decltype((b)) d = a; 
++c; 
++d;

Can someone explain to me the answer and why, along with some good (beginner-level) examples? A line-by-line explanation would be very helpful.


Solution

  • decltype is a way to specify a type: You give it an expression, and decltype gives you back a type which corresponds to the type of the expression, as explained in [dcl.type.simple] p4:

    The type denoted by decltype(e) is defined as follows:

    • if e is an unparenthesized id-expression or an unparenthesized class member access ([expr.ref]), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
    • otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
    • otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
    • otherwise, decltype(e) is the type of e.

    Note that the first bullet covers decltype(a), and the subsequent bullets cover double parentheses cases like decltype((b)).

    Combining these rules with reference collapsing rules allows you to make sense of decltype(e) &&, which is always a "suitable" reference. (C++14 also adds decltype(auto) to give you the type-deduction of auto combined with the value category semantics of decltype.)

    Examples

    int foo();
    int n = 10;
    
    decltype(n) a = 20;             // a is an "int"    [unparenthesized id-expression]
    
    decltype((n)) b = a;            // b is an "int &"  [(n) is an lvalue]
    decltype((std::move(n))) c = a; // c is an "int &&" [(std::move(n)) is an xvalue]
    decltype(foo()) d = foo();      // d is an "int"    [(foo()) is a prvalue]
    
    decltype(foo()) && r1 = foo();  // int &&
    decltype((n)) && r2 = n;        // int & [& && collapses to &]
    

    It might be worth stressing the difference between auto and decltype: auto works on types, and decltype works on expressions.

    You shouldn't be seeing or using decltype in "day-to-day" programming. It is most useful in generic (templated) library code, where the expression in question is not known and depends on a parameter. (By contrast, auto may be used generously all over the place.) In short, if you're new to programming, you probably won't need to use decltype for some time.