文章目录
C++的类型推导详解
auto & decltype
C++11引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能方便的获取复杂的类型,而且还能简化书写,提高编码效率。
auto :变量类型推断 & decltype :表达式类型推动
auto
1. 类型推导
auto类型推导:auto定义的变量,可以根据初始化的值,在编译时推导出变量名的类型,可以通过=右边的类型推导出变量的类型。
auto a = 10; //10是int型,可以自动推导出a是int
int i = 10;
auto b = i; //b是int型
auto d = 2.0; //d是double型
auto pi = new auto(1); //pi被推导为 int *
const auto *xp = &a,u=6; //xp是const int*类型,u是const int型
auto d = 0, f = 1.0; // error,0和1.0类型不同,对于编译器有二义性,没法推导
auto int b; //error c11中auto不再表示存储类型指示符
auto s; //error 没有初始化值 auto无法推导出s的类型
由此可以看出,auto并不能代表一个实际的类型声明(s),知识一个类型声明的占位符。使用auto声明变量必须要有初始化值,以让编译器推断出她的实际类型,并在编译时将auto占位符替换为真正的数据类型。
2.auto的推导规则
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 f = e; //f->int
const auto &g = x;//g->const int &
auto &h = g; //h->const int &
从上面的实力中可以看到auto
的一些使用方法。他可以同指针、引用结合起来使用,还可以带上 cv
限定符(const
等限定符)。
我们可以通过上面的实例得到以下两条规则:
- 当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符后类型一致。
- 当声明为引用或指针时,auto的推导结果将保持初始化表达式的cv属性。
3.auto作为函数的形参类型
void func(auto x)
{
cout<<sizeof(x)<<endl;
cout<<typeid(x).name()<<endl;//typeid:获取类型名
}
int main
{
int a = 10;
int ar[] = {1,2,3,4};
fun(a);
fun(ar);
}
void func(auto &x)
{
cout<<sizeof(x)<<endl;
cout<<typeid(x).name()<<endl;//typeid:获取类型名
}
int main
{
int a = 10;
int ar[] = {1,2,3,4};
fun(a);
fun(ar);
}
4. auto的限制
struct foo
{
suto value = 0; //error auto不能用于非静态成员变量
static const int num =10;// num->static const int
}
int main
{
int ar[10]={0};
auto br = ar; //br->int*
auto cr[10]=ar; //error auto无法定义数组
auto dr[5]={1,2,3,4}; //error auto无法定义数组
}
总结auto的限制:
- auto的使用必须马上初始化,否则无法推导出类型
- auto在一行定义多个变量时,各个变量的推导不能产生二义性,否则编译失败
- 在类中auto不能用作非静态成员变量
- auto不能定义数组,可以定义指针
- auto无法推导出模板参数
5. auto可以推导函数返回类型
template<class T>
T my_max(T a,T b)
{
return a>b?a:b;
}
int main
{
auto x=my_max(12,13);
auto y=my_max('a','b');
return 0;
}
decltype
auto用于通过一个表达式在编译时确定带定义的变量类型,auto所修饰的变量必须被初始化,编译器需要通过初始化来确定auto所代表的类型,即必须要定义变量。若希望谷得到类型而不需要(或不能)定义变量的时候,C++11新增了decltype关键字,用来编译时推导出一个表达式的类型。
语法格式:decltype(exp)//exp表示一个表达式
decltype的推导过程是在便是期完成的,并且不会真正极端表达式的值。
int mian
{
int x=10;
decltype(x) y=1; //y->int
const int &i=x;
decltype(i) j=y; //j->const int &
cosnt decltype(x) *p=&x; //p->const int *
decltype(x) *ip=&x; //ip->int *
decltype(ip) *pp=&ip//pp->int
}
函数表达式
int add(int a,int b)
{
return a+b;
}
int main
{
int x=10,y=20;
decltype(my_add(0,0)) z;
z=add(x,y);
return 0;
}
auto和decltpe的配合使用
auto和decltype一般配合使用在推导函数返回值的类型上
template<typename T, typename U>
return_value add(T t, U u) { // t和v类型不确定,无法推导出return_value类型
return t + u;
}
上面代码由于t和u类型不确定,那如何推导出返回值类型呢,我们可能会想到这种
template<typename T, typename U>
decltype(t + u) add(T t, U u) { // t和u尚未定义
return t + u;
}
这段代码在C++11上是编译不过的,因为在decltype(t +u)推导时,t和u尚未定义,就会编译出错,所以有了下面的叫做返回类型后置的配合使用方法:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
这段代码在C++11上是编译不过的,因为在decltype(t +u)推导时,t和u尚未定义,就会编译出错,所以有了下面的叫做返回类型后置的配合使用方法:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
返回值后置类型语法就是为了解决函数返回制类型依赖于参数但却难以确定返回值类型的问题。