auto
一、auto类型推导(在推导时,不能使auto有二义性)
auto定义的变量,可以根据初始化的值,在编译时推导出变量名的类型(auto必须初始化)
对于系统来说12.23认为是double, 12.23f为float
int main()
{
auto x=5; //ok x是int类型
auto pi = new auto(1); //ok pi 被推导为int *;
const auto *xp =&x ,u=6; //ok xp是const int*类型,u是const int类型
static auto dx=0.0; //ok dx是double类型
auto int b; //error C++11中auto不再表示存储类型指示符
auto s; //error 没有初始化auto无法推导出s的类型
}
int main()
{
auto x=5;
auto *ip=&x,y=10; //ip=>int*,y=>int auto=>int
auto sp=&x,z=10; //error sp=>int* auto=>int*
// z=>int auto=>int 此时出现二义性
const auto *xp=&x,u;//error u没有初始化,auto必须初始化
const auto *ip=&x,u=6;//ok
}
int main()
{
const int x=10;
auto xa=x; //xa=>int
auto &ya=x; //引用, ya=>const int &
auto &za=10;//error 无法做到常性引用
}
二、auto的推导规则
从上面的示例中可以看到auto的一些使用方法。它可以同指针、引用结合起来使用,还可以带上cv限定符。
int main()
{
int x=0;
auto *ip=&x; //ok ip->int* ,auto被推导为int
auto xp=&x; //ok xp->int* ,auto被推导为int*
auto &c=x; //ok c->int & ,auto被推倒为int
auto d=x; //ok d->int, auto被推导为int
const auto e=x; //ok e->const int;
auto f=e; //ok f->int;
const auto &g=x;//ok g->const int &
auto &h=g; //ok h->const int &
}
int main()
{
int a=10;
const int* ip=&a; //*ip不可变
auto p=ip; //p->const int* ,auto->const int* ,p=ip -> p=&a不可通过*p改变a的值
auto& s=ip; //s->const int*& ,auto->const int*
int* const sp=&a; //sp->&a 不可变,*sp可变
auto p2=sp; //p2->int* p2=&b不会影响sp=&a
auto& p3=sp; //p3->int* const &
return 0;
}
通过上面的一系列示例,可以得到下面这两条规则:
1.当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符后类型一致
2.当声明为指针或引用时,auto的推导结果保持初始化表达式的cv属性。
三、auto作为函数的形参类型
void func(auto x)
{
auto dx=12.23; //此时x的auto与dx的auto无关,不会出现二义性
cout<<sizeof(x)<<endl;
cout<<typeid(x).name()<<endl; //typeid(x).name输出的是x的类型名
}
int main()
{
int a=10;
int ar[]={12,23,34,45,56};
func(a); //sizeof=>4 typeid.name=>int
func(ar); //ar为首地址,sizeof=>4 typeid.name=>int *
}
void funr(auto &x) //引用
{
cout<<sizeof(x)<<endl;
cout<<typeid(x).name()<<endl;
}
int main()
{
int a=10;
int ar[]={12,23,34,45,56};
funr(a); //sizeof=>4 typeid.name=>int &
funr(ar); //sizeof=>20 typeid.name=>int [5]&
//传地址 x为ar的别名同一地址空间,并不是首地址
}
注意:
sizeof(ar); int(&br)[10]=ar; int(*p)[10]=ar;
只有在这三种情况下ar代表数组整体,其他情况代表数组首地址。
四、auto限制
struct Foo
{
auto value = 0; //error:auto不能用于非静态成员变量
static const int num = 10; //ok:num->static const int;
}
int main()
{
int ar[10]={0};
auto br=ar; //ok br->int*
auto &cr=ar;
auto cr[10]=ar; //error:auto无法定义数组
auto dr[5]={1,2,3,4,5}; //error:auto无法定义数组
}
总结:
1.C++中auto成为类型指示符
2.auto不能用于函数参数
3.auto不能用于非静态成员变量
4.auto无法定义数组
5.实例化模板时不能使用auto作为模板参数
6.auto不能设计结构体
7.auto无法推导结构体变量类型(auto x{" ljl ",12}; //error无法确定那个结构体)
五、auto可以推导函数的返回类型
template<class T>
T my_max(T a,T b)
{
return a>b?a:b;
}
int main()
{
auto x=my_max(12,23);
auto y=my_max('a','b');
cout<<x<<endl;
cout<<y<<enfl;
return 0;
}
struct Student
{
char s_name[20];
int s_age;
};
auto func()
{
struct Student x{"ljl",12};
return x;
}
decltype关键字
一、decltype的几种形式
int main()
{
int x=10; //decltype(x) c; 可以不用初始化
decltype(x) y=1; //y->int
decltype(x+y) z=0; //z->int
const int& i=x;
decltype(i) j=y; //有引用,要有初始值 j->const int&
const decltype(z)* p=&z; //p->const int* *p->const int
decltype(z)* ip=&z; //ip->int* *ip->int
decltype(ip)* pp=&ip; //pp->int** *pp->int* **pp->int
decltype(x+1) x1=x;
decltype(x+y) x2=x;
decltype((x)) rx=x; //rx=>int&
return 0;
}
decltype可以抓取cv特性
int main()
{
int a=10;
decltype(++a) ra=a; //++a返回该变量的引用 ra->int&
decltype(a++) rb=a; // ra->int
//a不会被+1,只在意类型,不运行ra=10,rb=10;
}
二、函数表达式
int add(int a,int b)
{
return a+b;
}
int main()
{
int x=10,y=20;
decltype(add(0,0)) z; //z->int
z=add(x,y);
}
三、decltype的推导规则
eg:decltype(exp) varName
1.如果exp是一个不被括号()包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,decltype(exp)的类型和exp一致
2.如果exp是函数调用,则decltype(exp)的类型就和函数返回值的类型一样
3.如果exp是一个左值,或被括号()包围,decltype(exp)的类型就是exp的引用,假设exp的类型为T,则decltype(exp)的类型为T&