What is decltype

Inspects the type of an entity/expression.
Why use decltype?
  When declaring types that are difficult or impossible to declare using standard notation, like lambda-related types or types that depend on template parameters.
SYNTAX?

decltype ( expression )         //Since C++11
decltype ( type )               //Since C++11
        

Variable declaration using decltype

1. char,int variable


#include <iostream>
int main(){
    char c;
    decltype(c) c1 = 10;
    std::cout << c1;                     //10
    std::cout << typeid(c1).name();      //char

    int a;
    decltype(a) b = 10;
    std::cout << typeid(b).name();      //int
}
        

2. Lambda


#include <iostream>
int main(){
    auto f = [](int a, int b)->int {
        return a*b;
    };
    decltype(f) c = f;
    std::cout << typeid(c).name();                //int
    std::cout << c(2,3);                          //6
}
        

3. Template Variable


template <typename T>
T add(T a, T b) {
    return a + b;
}

template <typename T, typename U>
auto add1(T a, U b) -> decltype(a + b) {
    return a + b;
}

int main() {
    decltype(add(2, 3)) a = 1;
    decltype(add(2.1, 3.1)) b = 2.3;
    cout << typeid(a).name() << "\n";       //int
    cout << a + b << "\n";                  //3.3

    decltype(add1(2, 1.1)) c = 3;
    cout<<<< typeid(c).name() << "\n";       //double
}
        

decltype auto

auto vs decltype(auto)

auto does not deduces the type correctly, decltype(auto) does.
auto decltype
cv-qualifiers(const, volatile) auto does not keep cv qualifiers

int main() {
    const int a = 10;
    auto a1 = a;
    cout << typeid(a1).name() << "\n";      //int
}
                    
decltype keeps the cv qualifiers

int main() {
    const int a = 10;
    decltype(auto) a1 = 2;
    if (is_same <int&, decltype(d)>::value) {
        cout << "yes";                            // yes
    }
    cout << typeid(a1).name() << "\n";      //const int
}
                    
int&

int y = 0;
int& y1 = y;
auto y2 = y1;           //y2 is int
                    

int y = 0;
int& y1 = y;
decltype(auto) y2 = 1;                    //y is int&
if (is_same <int&, decltype(y2)>::value) {
    cout << "yes";                            // yes
}
                    
int&& (R value reference)

int main() {
    int&& a = 0;    //R value reference
    auto a1 = move(a);
    cout << typeid(a1).name() << "\n";      //int
    if (is_same <decltype(a1), int&&>::value) {
        cout << "yes";
    } else {
        cout << "No";
    }
}
/*
Output:
No
*/
                    

int main() {
    int &&a = 0;
    decltype(auto) a2 = move(a);
    cout << typeid(a1).name() << "\n";      //int &&
    if (is_same <decltype(a2), int&&>::value)
        cout << "yes";
    else
        cout << "no";
}
/*
Output:
yes
*/
                    
Function Return type

auto fun (int &i) { // Function return type is int&, but auto returned int
    return i;
}
int main() {
    int a = 1;
    if (is_same <decltype(fun(a)), int&>::value) {
        cout << "yes" << endl;
    } else {
        cout << "no" << endl;
    }
}
/*
Output:
No
*/
                    

decltype(auto) fun1 (int &i) {
    return i;
}
int main() {
    auto a2 = fun1(a);
    if (is_same <decltype(a2), int&>::value) {
        cout << "yes";
    }
}
/*
Output:
yes
*/