编辑代码

#include <iostream>
using namespace std;
#include <string>
#include<list>
// 在某些情况下,不需要或者不能定义变量,但是希望得到某种类型,这时候就可以使用 C++11 提供的 decltype 关键字了,它的作用是在编译器编译的时候推导出一个表达式的类型,语法格式如下:


// decltype (表达式)
// decltype 是 “declare type” 的缩写,意思是 “声明类型”。decltype 的推导是在编译期完成的,它只是用于表达式类型的推导,并不会计算表达式的值。来看一组简单的例子:


// int a = 10;
// decltype(a) b = 99;                 // b -> int
// decltype(a+3.14) c = 52.13;         // c -> double
// decltype(a+b*c) d = 520.1314;       // d -> double
// 可以看到 decltype 推导的表达式可简单可复杂,在这一点上 auto 是做不到的,auto 只能推导已初始化的变量类型。

// 2.1 推导规则
// 通过上面的例子我们初步感受了一下 decltype 的用法,但不要认为 decltype 就这么简单,在它简单的背后隐藏着很多的细节,下面分三个场景依次讨论一下:

// 表达式为普通变量或者普通表达式或者类表达式,在这种情况下,使用 decltype 推导出的类型和表达式的类型是一致的。




// #include <iostream>
// #include <string>
// using namespace std;

// class Test
// {
// public:
//     string text;
//     static const int value = 110;
// };

// int main()
// {
//     int x = 99;
//     const int &y = x;
//     decltype(x) a = x;
//     decltype(y) b = x;
//     decltype(Test::value) c = 0;

//     Test t;
//     decltype(t.text) d = "hello, world";

//     return 0;
// }
// // 变量 a 被推导为 int 类型
// // 变量 b 被推导为 const int & 类型
// // 变量 c 被推导为 const int 类型
// // 变量 d 被推导为 string 类型
// // 表达式是函数调用,使用 decltype 推导出的类型和函数返回值一致。

// //函数声明
// int func_int();                 // 返回值为 int
// int& func_int_r();              // 返回值为 int&
// int&& func_int_rr();            // 返回值为 int&&

// const int func_cint();          // 返回值为 const int
// const int& func_cint_r();       // 返回值为 const int&
// const int&& func_cint_rr();     // 返回值为 const int&&

// const Test func_ctest();        // 返回值为 const Test

// //decltype类型推导
// int n = 100;
// decltype(func_int()) a = 0;		
// decltype(func_int_r()) b = n;	
// decltype(func_int_rr()) c = 0;	
// decltype(func_cint())  d = 0;	
// decltype(func_cint_r())  e = n;	
// decltype(func_cint_rr()) f = 0;	
// decltype(func_ctest()) g = Test();	
// 变量 a 被推导为 int 类型
// 变量 b 被推导为 int& 类型
// 变量 c 被推导为 int&& 类型
// 变量 d 被推导为 int 类型
// 变量 e 被推导为 const int & 类型
// 变量 f 被推导为 const int && 类型
// 变量 g 被推导为 const Test 类型
// 函数 func_cint () 返回的是一个纯右值(在表达式执行结束后不再存在的数据,也就是临时性的数据),对于纯右值而言,只有类类型可以携带const、volatile限定符,除此之外需要忽略掉这两个限定符,因此推导出的变量 d 的类型为 int 而不是 const int。




// 3表达式是一个左值,或者被括号 ( ) 包围,使用 decltype 推导出的是表达式类型的引用(如果有 const、volatile 限定符不能忽略)。

class Test{
    public:
    int num=9;
    string text;
    static const int value=110;

};

void func()
{
    const Test obj;
    //带有括号的表达式
    //a:int
    decltype(obj.num) a =0;
    //b: const int &   obj是常对象 并且加了小括号
    decltype((obj.num)) b=a;
    //加法表达式
    int n=0,m=0;
    //c:int
    decltype (n+m) c=0;
    //d:int &    表达式是一个左值,则推导出的它的引用
    decltype(n=n+m) d=n;
    

}


//decltype的应用

//在泛型编程中,比如我们编写一个类模板,在里边添加遍历容器的函数,操作如下:

template<class T>
class Container
{
    public:
    void print(T &t)
    {
        for(m_it=t.begin(); m_it!=t.end();++m_it)
        {
            cout<<"value:"<<*m_it<<endl;
        }
    }

    private:
    //T::iterator m_it;    err T不能是迭代器的类型
    decltype(T().begin()) m_it;  //通过对匿名对象的推导来实现。   

};

void func2()
{
    list<int> ls{1,2,3,4,5,6,7};
    const auto it=ls.begin();    //只读迭代器。
    Container<const list<int>>c;
    c.print(ls);

}

//返回类型后置 
//在泛型编程中,可能需要通过参数运算来得到返回值的类型,比如下面这个场景。

//R->返回值类型, T->参数1类型,  U->参数2类型 
template <class R,class T ,class U >
R add(T t,U u)
{
    return t+u;
}

//返回值后置写法
//auto func(参数1,参数2) ->decltype(参数表达式)

template <class T ,class U >
auto add1(T t,U u) ->decltype(t+u)
{
    return t+u;
}

void func3()
{
    int x=520;
    double y=13.14;
    auto ret=add<decltype(x+y),int,double>(x,y);  //不符合逻辑,我们看不到返回值的类型,应该在编写模板的时候就推导好。
    cout<<"ret:"<<ret<<endl;     //double

    auto ret1=add1<>(x,y);
    cout<<"ret1:"<<ret1<<endl;     //double
}

int main()
{

    func();
    func2();
    func3();
    return 0;
}