使用auto或decltype作为类型缩写
Code:
string line;
// read input a line at a time and print lines that are longer than 80 characters
while (getline(cin, line))
if (line.size() > 80)
cout << line << endl;
此处line.size()
返回一个string::size_type
类型的数值。
string::size_type
类型是string类定义的内置类型,目的是实现代码的可移植性。使用该类型时需要添加域限制符sring::
。虽然我们不知道string::size_type
的确切类型,但是我们知道它是一个大小足以容纳任何字符串大小的无符号类型。用于存储string size
操作结果的任何变量都应为string::size_type
类型。我们在声明变量时使用string::size_type
类型说明符是冗长的。新标准下,我们可以使用auto
或decltype
来要求编译器提供适当的类型。
Code:
auto len = line.size(); // len has type string::size_type
注:在size()
表达式中不使用int,可以避免由于unsigned和int之间的转换而导致的问题。
for 范围声明(Range for Statement)
如果我们想对字符串中的每个字符执行某些操作,到目前为止,最好的方法是使用新标准引入的语句:for 范围声明。 此语句遍历给定序列中的元素,并对该序列中的每个值执行一些操作。 句法形式是:
for (declaration: expression)
statement
其中expression
是表示序列的类型的对象,而declaration
定义了我们将用于访问序列中的元素的变量。 在每次迭代中,declaration
由expression
中下一个元素的值初始化。
string
表示一个字符序列,所以我们可以使用一个string
类型的变量来作为for范围声明中的expression
。举个例子,我们可以使用for范围声明来打印string
类型变量中的每个字符:
Code:
string str("some string");
// print the characters in str one character to a line
for (auto c : str) // for every char in str
cout << c << endl; // print the current character followed by a newline
针对此处代码我们可以说按先后顺序每行打印一个str
中的字符c
。
for范围声明是根据传统for循环的等价物来定义的:
Code:
vector<int> v = {0,1,2,3,4,5,6,7,8,9};
// the traditional for
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) {
auto &r = *beg; // r must be a reference so we can change the element
r *= 2; // double the value of each element in v
}
// the range for
// range variable must be a reference so we can write to the elements
for (auto &r : v) // for each element in v
r *= 2; // double the value of each element in v
for范围声明简化了for循环的编写,这个新特性可以认为C++吸收了其他语言(如:Java)优秀特性的一个例子。
vector嵌套定义
早期版本C++在使用向量的向量(vector of vectors)时,声明是在两个>
之间需要加入空格,而新版本中则不需要加入空格,如下所示:
Code:
vector<vector<int> >; // Older version about defining a vector whose elements are themselves vectors
vector<vector<int>>; // C++11 about defining a vector whose elements are themselves vectors
注:一些编译器可能仍然要求旧式声明
列表初始化vector
新标准下,我们可以列出初始化列表来初始化一个vector。该初始化列表由花括号及其中零个或多个元素数值组成:
Code:
vector<string> articles = {"a", "an", "the"}; //articles consists of three elements
容器函数cbegin和cend
容器函数begin
和end
返回的类型依赖于它们作用的对象是否是const
。如果对象是const
,那么begin
和end
都返回const_iterator
;如果对象不是const
那么它们都返回iterator
。
Code:
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); // it1 has type vector<int>::iterator
auto it2 = cv.begin(); // it2 has type vector<int>::const_iterator
通常在只需要读取对象而不需要写入时,我们最好使用const类型的迭代器(如:const_iterator
)。为了让我们能专门使用const_iterator
类型,新标准引入了两个名为cbegin
和cend
的新函数:
Code:
auto it3 = v.cbegin(); // it3 has type vector<int>::const_iterator
和容器函数begin
和end
一样,cbegin
返回指向第一个元素的迭代器,cend
返回指向最后一个元素后一位置的迭代器。但是不论容器(如:vector或string)是否为const,它们都会返回const_iterator
。
库函数begin和end
虽然我们可以手动计算出数组的始末下标,但是这样做很容易出错。为了能更容易和安全地使用这类下标指针,新标准下标准库中引入了两个函数begin
和end
。这两个函数与容器类中的成员函数begin
和end
的行为类似。然后当我们使用数组类型时,由于数组类型不是容器类,所以针对数组类型我们往往使用库函数begin
和end
,同时这两个函数的参数是相应的数组类型变量:
Code:
int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia is an array of ten ints
int *beg = begin(ia); // pointer to the first element in ia
int *last = end(ia); // pointer one past the last element in ia
begin
返回一个指向数组中第一个元素的指针,end
返回一个指向数组中最后一个元素的后一位置的指针,这两个函数定义在头文件iterator
中。
使用auto和decltype简化声明
新标准中,我们可以使用auto
和decltype
来避免写明指向数组的指针类型,从而简化声明。
Code:
// print the value of each element in ia, with each inner array on its own line
// p points to an array of four ints
for (auto p = ia; p != ia + 3; ++p) {
// q points to the first element of an array of four ints; that is, q points to an int
for (auto q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}
外部for
循环首先将p
初始化为指向数组ia
中的第一个元素。该循环一直持续到我们在ia
中处理了所有三行。增量++p
具有将p移动到指向ia
中的下一行(即下一个元素)的效果。
内部for
循环打印内部数组的值。首先使q
指向p
指向的数组中的第一个元素。*p
操作的结果是获得含有四个整数的数组,当我们使用该数组时,它会自动转换为指向其第一个元素的指针。内部for
循环一直运行到我们处理了内部数组中的每个元素。为了获得一个指向内部数组末尾的指针,我们再次解引用p
以获取指向该数组中第一个元素的指针,然后我们将4添加给该指针以得到内部数组末尾的指针。
当然,我们甚至可以使用库函数begin
和end
更容易地编写这个循环:
Code:
// p pointsto the first array in ia
for (auto p = begin(ia); p != end(ia); ++p) {
// q points to the first element in an inner array
for (auto q = begin(*p); q != end(*p); ++q)
cout << *q << ' '; // prints the int value to which q points
cout << endl;
}
这里我们使用库函数end
确定结束指针,使用auto
来避免写入从begin
返回的类型。在外部循环中,该类型是指向含有四个int
的数组的指针;在内部循环中,该类型是指向int
的指针。
参考文献
[1] Lippman S B , Josée Lajoie, Moo B E . C++ Primer (5th Edition)[J]. 2013.