【C++】C++11新特性

一、auto类型推导

auto这个关键字其实在C++11之前就已经存在了,在C++98中的auto关键字的作用是指明变量的存储类型,与static相对,在比较老C++书籍中可以找得到相关内容,只是在我们的实际编程中基本上被忽略,这是因为我们在创建变量时默认的存储类型就是auto—自动存储类型的,不需要显示表示,只有在需要声明静态变量时才会显示表示static,以指明变量的存储类型为静态存储类型。如:

1
2
3
auto int a = 0;
int b = 0;
static int c = 0;

这里a和b的存储类型都是auto类型。

在C++11之后,C++标准摒弃了C++98的auto关键字的用法,将auto关键字的功能换成了自动类型推导,就和现在大多数脚本语言中的var一样。

 需要注意的是,在自动类型推导中,小数会被默认推导成double类型而不是float。

auto的出现并不意味着C++变成了弱类型语言,auto在程序中仅仅只起到占位符的作用,在编译期间它才会被替换成具体的类型,所以在运行时类型依然是明确的。

auto关键字支持多变量声明,但是同时声明的变量必须是同一类型的,否则会出现编译不通过的错误。如:

1
auto a = 1,b = 1.1;

这种情况会报错。

 在声明auto变量时,必须对变量进行初始化。这种情况是语法错误:

1
auto a,b;

auto、指针与引用

先来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
int a = 0;
auto *p1 = &a;
auto p2 = &a;
auto p3 = p1;
auto &r1 = a;
auto r2 = r1;


cout << typeid(p1).name() << endl;
cout << typeid(p2).name() << endl;
cout << typeid(p3).name() << endl;
cout << typeid(r1).name() << endl;
cout << typeid(r2).name() << endl;

输出结果:

1
2
3
4
5
int *
int *
int *
int
int

可以看到auto推导出了指针类型,却忽略了&类型,这一点是需要注意的。

auto与const

还是先来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
const int a = 0;
auto c1 = a;
const auto c2 = a;
const auto *p = &a;
const auto &r1 = a;
auto &r2 = r1;

cout << typeid(c1).name() << endl;
cout << typeid(c2).name() << endl;
cout << typeid(p).name() << endl;
cout << typeid(r1).name() << endl;
cout << typeid(r2).name() << endl;

输出结果:

1
2
3
4
5
int
int
int const *
int
int

可以看到除了指针类型,其他的都被推导成了int类型,我们再在上面的代码中加一些代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const int a = 0;
auto c1 = a;
const auto c2 = a;
const auto *p = &a;
const auto &r1 = a;
auto &r2 = r1;

cout << typeid(c1).name() << endl;
cout << typeid(c2).name() << endl;
cout << typeid(p).name() << endl;
cout << typeid(r1).name() << endl;
cout << typeid(r2).name() << endl;

int b = 0;
c1 = 2;
c2 = 2;
p = b;
r1 = 2;
r2 = 2;

当我们添加了这段代码之后,除了c1=2,其他的行都会报语法错误,所以尽c2,r1,r2被推导为int类型,但是const的约束依旧存在,但是c1没有报语法错误,也就是说c1实际上是非const类型,即auto c1 = a,在默认情况下auto将c1推导为非常量,如果需要设置为常量则需要显示标识const。

关于typeid().name() 有一点很迷,就是在C++的语法中,只有常量指针类型在类型名上带有const,如上面的int const *,而其他的无论是指针常量、常量引用在类型上都是忽略const的,但是在我们把一个变量常量的地址赋予一个非常量指针时,则会报:

在网上没有找到相关的解析,推测在C++语法上是只有常量指针类型带有const,没有其他的带有const的类型的,而出现上面的提示十有八九是编辑器做的,而非C++本身的。

总结

  • auto的作用是类型推导,本质是占位符,在编译阶段,编译器会将正确的类型替换到auto位置上;
  • auto可以和任何类型搭配,包括指针与引用;
  • 在声明auto变量时必须对uto变量初始化;
  • auto关键字可以用作函数返回值类型。

二、decltype类型推导

由于auto的使用在有些方面上收到限制,比如,声明auto变量时必须对变量进行初始化,而在实际使用时,可能没法进行初始化,于是decltype就出现了,decltype也是C++的一个关键字。

decltype通过表达式来推导类型,表达式可以是一个变量、常量、或者函数,使用形式为decltype(exp),exp为表达式如:

1
2
3
4
5
6
7
8
9
10
auto fun(int* a)
{
return *a * 0.2f;
}

int main()
{
int b = 0;
decltype(fun(&b)) a;
}

和auto一样decltype也可以用作函数返回值类型。

decltype与auto的区别

  • auto关键字声明的变量必须初始化,decltype不需要;
  • auto在类中只能用于定义静态成员,decltype可以用于任何成员;
  • decltype的使用上比auto更灵活;
  • auto更具初始值来推导类型,decltype根据表达式来推导类型。

三、返回类型后置语法

有时候我们写函数需要用到函数参数来推导,由于C++的返回值是前置语法,所以返回值是无法使用函数参数的,于是便有了返回值类型后置语法,先看一个例子:

1
2
3
4
5
template<typename T,typename U>
auto fun(T a,U b)->decltype(a+b)
{
return a+b;
}

返回值类型后置语法可以将decltype使用参数推导出的类型赋予auto中,所以在这个语法中auto,decltype是必不可少的。

我们仔细思考后会发现好像直接这样使用也是可以达到最终效果的:

1
2
3
4
5
template<typename T,typename U>
auto fun(T a,U b)
{
return a+b;
}

那么返回值后置类型语法的作用又是什么呢?事实上我们在多想一下就会明白,auto fun(T a,U b)->decltype(a+b)语法把auto的类型限制在decltype(a+b)的推导类型的范围内了,而auto fun(T a,U b)中auto是可以为任何类型的。但是在大多数使用场景下似乎还是没什么区别。

到这里只有一句感叹,C++在类型推导上相较于主流脚本语言的类型推导还是薄弱了很多很多。

四、左值与右值


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!