C++11引入了auto(类型识别)和decltype(类型推演)关键字实现类型推导,通过这两个关键字不仅能方便地获取复杂的类型,而且还能简化书写,提高编码效率。
一、auto关键字
C11中auto成为类型指示符(type-specifier)。
auto类型推导: auto定义的变量,可以根据初始化的值,在编译时推导出变量名的类型。
int main()
{
auto a = 10;//a int
auto ip = new auto(1);//1 是整型,将整型的地址给ip, ip int*
auto dp = new auto(12.23);//dp double*
return 0;
}
1)auto 推导类型不能有二义性
int main()
{
auto x = 5;//int
const auto* ip = &x;//ip int *,auto是int
//const auto* ap = &x, u;//error ,u没有初始值,不能推演,必须给出初始值才可以推演
const auto* ap = &x, u=10;//ok,虽然前面已经推导出auto的类型为int,但后面u仍然必须写初始值
const auto* ap = &x, u = 12.23;//error,由&x可以推出auto是int,但是u=12.23,那么auto就得是double,这样具有二义性
return 0;
}
2)auto 推导类型变量必须初始化
不初始化无法推导类型。
int main()
{
auto s;//error,没有初始化,无法推导
auto int y;//error,auto 在c11中是推导类型,不再表示存储类型指示符
return 0;
}
3)auto的推导规则
auto可以同指针、引用结合起来使用,还可以带上cv限定符(cv-qualifier(修饰词),const和volatile限定符的统称)
int main()
{
int x = 0;
auto* ip = &x;//ip->int *,auto 被推导为int
auto xp = &x;//xp->int *,auto int *
auto& c = x;//c->int &,auto int
auto d = x;//d-> int,auto int
const auto e = x;//e->const int,auto int
auto f = e;//f->int ,auto int
const auto& g = x;//g->const int &,auto
auto& h = g;//h->const int &
//h是g的别名,g是const int&,不能通过h改变g,
//h += 10;//error,h是常量,无法赋值
auto y = g;//y->int,y= g,相当于将数值g给变量y
return 0;
}
ip和c的推导结果是很显然的,auto在编译时被替换为int,因此a和c分别被推导为int*和int&。
xp的推导结果说明,其实auto 不声明为指针,也可以推导出指针类型。
d 的推导结果说明当表达式是一个引用类型时,auto 会把引用类型抛弃,直接推导成原始类型int。
e的推导结果说明,const auto会在编译时被替换为const int。
f的推导结果说明,当表达式带有const(实际上volatile也会得到同样的结果)属性时,auto会把const属性抛弃掉,推导成non-const类型int。
g、h的推导说明,当auto和引用(换成指针在这里也将得到同样的结果)结合时,auto的推导将保留表达式的const属性。
通过上面的一系列示例,可以得到下面这两条规则:
1)当不声明为指针或引用时,auto 的推导结果和初始化表达式抛弃引用和cv限定符后类型一致。2)当声明为指针或引用时,auto的推导结果将保持初始化表达式的cv属性。
4)auto 作为函数的形参类型
对于auto作为函数形参类型,版本要求很高,要提高属性设置的版本
设置步骤:
如此,auto才可以作为函数的参数类型
void func(auto x)
{
cout << sizeof(x) << endl;
cout << typeid(x).name() << endl;
}
#include<iostream>
#include<typeinfo>
using namespace std;
void func(auto x)
{
cout << sizeof(x) << endl;
cout << typeid(x).name() << endl;
}
int main()
{
int a = 10;
int ar[] = { 1,2,3,4,5,6,7,8 };
func(a);
func(ar);//此时ar作为数组首元素的地址
return 0;
}
参数引用
#include<iostream>
#include<typeinfo>
using namespace std;
void func(auto &x)
{
cout << sizeof(x) << endl;
cout << typeid(x).name() << endl;
}
int main()
{
int a = 10;
int ar[] = { 1,2,3,4,5,6,7,8 };
func(a);
func(ar);//引用数组,数组有两个属性,大小和类型
//数组体现两个属性的地方:sizeof(ar);指针int(*p)[8]=&ar;引用 int (&br)[8]=ar;
return 0;
}
int main()
{
int a = 10;
int ar[] = { 1,2,3,4,5,6,7,8 };
auto b = ar;//b->int *
auto& c = ar;//c->int (&c)[8]
cout << sizeof(b) << endl;//8
cout << sizeof(c) << endl;//32
return 0;
}
5)auto的限制
struct Foo
{
auto value = 0;//error,auto不能用于非静态成员变量
static const int num = 10;//ok,num->static const int,必须是const和整型才可以用auto推导
};
int main()
{
auto ar[] = { 1,2,3,4 };//error;auto只能推导基本数据类型,无法定义数组
return 0;
}
1、C11中auto成为类型指示符(type-specifier)。
2、auto不能用于函数参数。
3、auto不能用于非静态成员变量
4、 auto无法定义数组
5、实例化模板时不能使用auto作为模板参数。
6)auto可以推导函数的返回类型
#include<iostream>
using namespace std;
template<typename T>
const T& Max(const T& a, const T& b)//引用返回
{
return a > b ? a : b;
}
int main()
{
auto a = Max(12, 23);//auto 可以推导出函数的返回值类型,值返回,以值的形式接收
auto& b = Max(23, 34);//b ->const int &,引用接收,常性引用返回,
//对于模板函数来说,用auto 接收函数的返回值,不用判断返回值类型是什么,可以直接接收,比较方便
auto x = Max(24,25);
auto y = Max('a','b');
return 0;
}
二、decltype
auto,用于通过一个表达式在编译时确定待定义的变量类型,auto所修饰的变量必须被初始化,编译器需要通过初始化来确定auto所代表的类型,即必须要定义变量。
若仅希望得到类型,而不需要(或不能)定义变量的时候应该怎么办呢?
C++11新增了decltype关键字,用来在编译时推导出一个表达式的类型,
它的语法格式如下:
decltype (exp)
其中,exp表示一个表达式(expression)
从格式上来看,decltype很像sizeof——用来推导表达式类型大小的操作符。
类似于sizeof,decltype的推导过程是在编译期完成的,并且不会真正计算表达式的值。
int main()
{
int a = 10;
cout << sizeof(a + 10) << endl;//4
cout << sizeof(a + 10.25) << endl;//8
sizeof(++a);//sizeof计算类型的大小,只关心类型的大小,在编译期计算大小,不会真正计算表达式的值
int x = sizeof(++a);//x = 4
cout << a << endl;//10
return 0;
}
类型的推演都是发生在编译期。
auto与decltype 的区别:
int main()
{
int x = 10;
decltype(x)y = 1;//x是int,推演出y也是int
decltype(x + y) z = 10;
decltype(x + y + 10.23)a = 10;//10.23是double,所以整体是double
return 0;
}
int main()
{
int x = 10;
const int& a = x;//a是const int&
decltype(a)b = x;//推导出b也是const int &
//auto和decltype有些不同
auto z = a;//a是const int&,在此相当于将数值直接给z,z是int
auto& zz = a;//auto与引用、指针结合时,会保留const属性,zz是const int &
return 0;
}
int main()
{
int a = 10;
const int* ip = &a;
auto p1 = ip;//推导出p是const int *
decltype(ip)p2 = &a;//p2是const int *
return 0;
}
int my_add(int a, int b)
{
return a + b;
}
int main()
{
auto x = my_add(12, 23);//使用auto就会调用后面函数计算表达式的值,若我们只想得到返回类型,就可以使用declpyte
decltype(my_add(12, 23))z;//使用declpyte不会计算表达式的值,只是在编译期得到表达式的返回类型
z = my_add(12, 23);//z ->int
return 0;
}