C++11

C++11初始化

C++11 初始化方法(以{}方式初始化时进行的转换)

C++11将使用大括号的初始化称为列表初始化(list-initialization),因为这种初始化常用于给复杂的数据类型提供值列表。与传统的初始化方式相比,它对类型转换的要求更严格。具体地说,列表初始化不允许缩窄(narrowing),即变量的类型可能无法表示赋给它的值。例如,不允许将浮点型转换为整型。在不同的整型之间转换或将整型转换为浮点型可能被允许,条件是编译器知道目标变量能够正确地存储赋给它的值。例如,可将 long 变量初始化为 int 值,因为long 总是至少与int 一样长;相反方向的转换也可能被允许,只要int变量能够存储赋给它的long 常量:

	const int code = 66;
	int x = 66; 
	char cl31325;	//narrowing,not allowedchar 
	char c2 ={66};	//allowed because char can hold 66
	char c3{code};	// ditto
	char c4={x};	//not allowed,xis not constant
	x= 31325;
	char c5 = x;	//allowed by this form of initialization

数组的初始化规则

数组以前就可使用列表初始化,但C++11中的列表初始化新增了一些功能。首先,初始化数组时,可省略等号(=):

	double earnings[4]{ 1.2e4,1.6e4,1.1e4,1.7e4 };// okay with C++11

其次,可不在大括号内包含任何东西,这将把所有元素都设置为零:

	float balances[100]{};			//all elements set to 0
	unsigned int counts[10] = );	//all elements set to 0

第三,列表初始化禁止缩窄转换:

	long plifs[] = {25,92,3.0};				//not allowed
	char slifs[4]{'h','i','1122011','\0'};	// not allowed
	char tlifs[4]{'h','i','112','\0'};		// allowed

在上述代码中,第一条语句不能通过编译,因为将浮点数转换为整型是缩窄操作,即使浮点数的小数点后面为零。第二条语句也不能通过编译,因为1122011超出了char变量的取值范围(这里假设char变量的长度为8位)。第三条语句可通过编译,因为虽然112是一个int值,但它在char 变量的取值范围内。

C++11 字符串初始化

C++11也允许将列表初始化用于C-风格字符串和string 对象:

	char first date[] = { "Le chapon Dodu" };
	char second date[]{ "The Elegant plate" }; 
	string third date[] = ("The Bread Bowl"); 
	string fourth datef"Hank's Fine Eats";

表达式中的转换(C++11)

编译器通过校验表来确定算术表达式中执行的转换。下面是C++11版本的校验表

如果有一个操作数的类型是long double,则将另一个操作数转换为long double。
否则,如果有一个操作数的类型是double,则将另一个操作数转换为double。
否则,如果有一个操作数的类型是float,则将另一个操作数转换为float。
否则,说明操作数整型,因此执行整型提升。
在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作的级别比有符号操作数高,则将有符号转换为无符号操作数所属的类型。
否则,如果有符号类型可表示无符号类型的所有可能取值,将无符号操作数转换为有符号操作数所属的类型。
否则,将两个操作数都转换为有符号类型的无符号版本。

C++11 中的 auto 声明

	std::vectorscores; 
	std::vector::iterator pv = scores.begin();

    C++11 允许将其重写为下面这样:

	std::vectorscores;
	auto pv = scores.begin();

模板类arry(C++11)

vector 类的功能比数组强大,但付出的代价是效率稍低。如果您需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。有鉴于此,C++11新增了模板类 array,它也位于名称空间 std中。与数组一样,array 对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便,更安全。要创建aray对象,需要包含头文件array。array 对象的创建语法与vector 稍有不同:

	#include 
	...
	using namespace std;
	array ai;	//create array object of 5 ints
	array ad = { 1.2,2.1,3.43,4.3 };

推而广之,下面的声明创建一个名为arr 的 array 对象,它包含n_elem 个类型为 typename 的元素:
array arr;

与创建 vector 对象不同的是,n_elem 不能是变量。
在 C++11中,可将列表初始化用于 vector 和 array 对象,但在 C++98 中,不能对 vector 对象这样做。

基于范围的 for循环(C++11)

C++11新增了一种循环:基于范围(range-based)的for 循环。这简化了一种常见的循环任务:对数组(或容器类,如 vector 和 array)的每个元素执行相同的操作,如下例所示:

	double prices[5] = { 4.99,10.99,6.87,7.99,8.49 }; 
	for (double x : prices)
		cout << x << std::endl;

其中,x最初表示数组 prices 的第一个元素。显示第一个元素后,不断执行循环,而x依次表示数组的其他元素。因此,上述代码显示全部5个元素,每个元素占据一行。总之,该循环显示数组中的每个值。
要修改数组的元素,需要使用不同的循环变量语法:

	for (double &x : prices)
		x = x * 0.80;	//20% off sale

符号&表明x是一个引用变量,让接下来的代码能够修改数组的内容,而第一种语法不能。

还可结合使用基于范围的for循环和初始化列表,这种循环主要用于各种模板容器类:

	for (int x : { 3, 5, 2, 8, 6 })
		cout << x << " "; 
	cout << '\n';

C++11右值引用(rvalue reference)

右值引用可指向右值,是使用&&声明的:

	double && rref = std::sqrt(36.00);// not allowed for double &
	double j=15.0;					
	double && jref = 2.0*j + 18.5;	//not allowed for double &
	std::cout << rref << '\n';		// display 6.0
	std::cout << jref << '\n';		// display 48.5;


新增右值引用的主要目的是,让库设计人员能够提供有些操作的更有效实现。第18章将讨论如何使用右值引用来实现移动语义(movesemantics)。以前的引用(使用&声明的引用)现在称为左值引用。

关键字 decltype(C++11) 

作用:解决函数模板中,类型的声明问题

为确定类型,遍历核对表过程:

假设有如下声明:

	decltype(expression) var;

1.如果 expression 是一个没有用括号括起的标识符,则 var 的类型与该标识符的类型相同,包括 const 等限定符:

	double x = 5.5; 
	double y = 7.9; 
	double &rx = x;
	const double *pd;
	decltype(x)w;		// w is type double
	decltype(rx)u = y;	//u is type double &
	decltype(pd)v;		//vis type const double *

2.如果 expression 是一个函数调用,则 var 的类型与函数的返回类型相同:

	long indeed(int); 
	decltype(indeed(3))m;//mis type int

注意:并不会实际调用函数。编译器通过查看函数的原型来获悉返回类型,而无需实际调用函数

3.expression 是用括号括起的标识符,则var 为指向其类型的引用。:

	double xx = 4.4;
	decltype((xx))r2 = xx;//r2 is double &

4.如果前面的条件都不满足,则var的类型与expression 的类型相同: 

	int j = 3; 
	int &k = j;
	int & n = j;
	decltype(j + 6)il;		// il type int
	decltype(100L)i2;	//i2 type long
	decltype(k+n)i3;	// i3 type int;

请注意,虽然k和n都是引用,但表达式k+n不是引用;它是两个imnt的和,因此类型为int。

如果需要多次声明,可结合使用typedef和decltype:

template
void ft(Tl x, T2 y)
{
	typedef decltype(x + y)xytype;
	xytype xpy = x + y;
	xytype arr[10];
	xytype &rxy = arr[2];	//rxy a reference
}

C++11后置返回类型(另一种声明语法auto) 看下方伪代码:

template 
?type?  gt(T1 x, T2 y)
{
	return x + y;
}

无法预先知道将x和y相加得到的类型,函数返回值类型出还未声明参数x和y,它们不在作用域内,无法使用decltype(x+y)。此时可以使用auto,auto个占位符,表示后置返回类型提供的类型。上述代码修改如下:

template  
auto gt(T1 x, T2 y)->decltype(x+y)
{
	return x + y;
}

现在,decltype在参数声明后面,因此x和y位于作用域内。

你可能感兴趣的:(C++,c++)