1.decltype一般用法(获取类型)
int fun();
int main(void)
{
int inta = 2;
/*1.inta 为int.*/
decltype(inta ) a;
/*2.b为int,对于b根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用fun().*/
decltype(fun()) b;
return 0;
}
double tempA = 3.0;
const double ctempA = 5.0;
const double ctempB = 6.0;
const double *const cptrTempA = &ctempA;
/*1.dclTempA推断为const double(保留顶层const,此处与auto不同)*/
decltype(ctempA) dclTempA = 4.1;
/*2.dclTempA为const double,不能对其赋值,编译不过*/
dclTempA = 5;
/*3.dclTempB推断为const double * const*/
decltype(cptrTempA) dclTempB = &ctempA;
/*4.输出为4(32位计算机)和5*/
cout<<sizeof(dclTempB)<<" "<<*dclTempB<<endl;
/*5.保留顶层const,不能修改指针指向的对象,编译不过*/
dclTempB = &ctempB;
/*6.保留底层const,不能修改指针指向的对象的值,编译不过*/
*dclTempB = 7.0;
2.decltype与引用(主要是为了获取引用关系)
decltype是为了获取变量或者表达式的类型而存在,其主要作用是可以获取引用关联(&),甚至是为了确认左值!
- 当decltype(A),A为变量的时候,const int& i = 1;decltype(i)为const int&,即就是变量的类型;
- 当A为表达式的时候,如果该表达式的值是左值,则返回T&,例如int* p= 1;decltype(*p)为int&,同理deque vector等,deque< int > a{1,2,3}; decltype(a[])为int&, 因为表达式a[]可以当左值(deque里operator[]的返回值为T&,所以为左值引用类型,必为左值),同理数组的[]也是左值,如果class A里的operator[]不是左值,是返回int,decltype(a[])为int
- decltype可以形别推导,例如decltype(auto) 即保证形别与返回值或者=右边的值得类型完全一致!因为使用函数模板或者auto推导的时候,会去除引用&,decltype可以恢复
2.1 先区分左值与左值引用的关系
这里首先要区分左值引用、右值引用和左值、右值的关系
- int i = 1; int& a = i; 这里a是左值,其decltype(a)为int&,为左值引用,只能等于左值
- int&& b = 1; b为左值,但是其是右值引用,只能等于右值
- fun(T&),只能接收左值,不管其类型是左值引用还是右值引用
- fun(T&&),如果是万能引用则左值或者右值都能接收,但是如果确定T为int,则只能接收右值
- 左值是可以放在等号左边的,比如*p,或者vector()[],是可以被赋值的
- 右值只能放在等号右边,比如函数返回值为int,其只能在等号右边
2.2 decltype结合auto推导分析
先复习下函数模板和auto参数推导,auto与fun一致
- fun(T a) — 先去除&,const,例子:const int& x, fun(x)为(T为int),为值传递
- fun(T& a) — x只能为左值,且x要去除引用,例子,const int&& x,则T& a = const int,T为const int,PT为const int& ,x为const int&&,也就是说PT不一定为x,右值形参只能传右值,不去除&&
- fun(T&& a) — 万能引用,判断x为左值还是右值
- 注意函数参数与数组参数,void fun(int a),如果是第一种,则void()(int),如果是第二种void(&)(int),数组第一种为int,形参为int(&)[n]
例子1:
vector<int> a{1,2,3};
auto testa = a[1];//a[1]为int&,auto为template<T> fun(T t) --去除const与&,为int
decltype(testa) = a[1]// a[1]为int&, 左边为int&
例子2:
这种auto在前的返回值,不代表是auto推导类型,而是占位,实际推导为decltype(c[i]),这里为T&
auto authandAcess(Container& c, Index i)->decltype(c[i])
1、T&
template<typename Container, typename Index>
auto authandAcess(Container& c, Index i)->decltype(c[i])
{
return c[i];
}
2、返回的是个右值T,因为auto-return为函数模板推导,T~T&,结果会去除&,如果authandAcess(d,5)= 10;会报错,因为前面函数返回了右值
template<typename Container, typename Index>
auto authandAcess(Container& c, Index i)
{
return c[i];
}
3、C++14写法
template<typename Container, typename Index>
decltype(auto) authandAcess(Container& c, Index i))
{
return c[i];
}
4、完美转发版本
template<typename Container, typename Index>
decltype(auto) authandAcess(Container&& c, Index i))
{
return std::forward<Container>(c)[i];
}
Widegt w;
const Widget& cw = w;
auto myWidegt = cw;//这时符合auto T模式,值传递,const/&都消掉,myWidegt为Widegt
decltype(auto) myWidegt = cw 为const Widegt&
3. 关于测试decltype
代码:
template<typename _Tp>
struct remove_reference11
{ typedef _Tp type;
int i;
void fun(){cout<<"1111"<<endl;}};
template<typename _Tp>
struct remove_reference11<_Tp&>
{ typedef _Tp type; int i;
void fun(){cout<<"2222"<<endl;}};
template<typename _Tp>
struct remove_reference11<_Tp&&>
{ typedef _Tp type; int i;
void fun(){cout<<"3333"<<endl;}};
class testcc
{
public:
int operator[](int num)
{
return num;
}
int a;
};
testcc cc;
remove_reference11<decltype(cc[2])> ppp; //int
int i;
remove_reference11<decltype(std::move(i))> // int&&
vector<int> t{1,2,3}
remove_reference11<decltype(t[1])> //int&