1.tuple类型:
每个tuple的成员类型可以都不相同,可以有任意数量的成员。
tuple<string, vector<double>, int> someVal("Contants", {2.1, 3.6, 9}, 32);
pair总有两个成员(first和second),tuple的成员个数不确定,所以不能用这种方式访问。
要访问tuple的成员,就要使用名为get的标准库函数模板。
auto nVal = get<2>(someVal); // 返回someVal的第3个成员
tuple_size和tuple_element可以获得到tuple成员的数量和某个成员,前提是知道tuple的类型。
typedef decltype(someVal) trans; // trans是someVal的类型
size_t sz = tuple_size<trans>::value; // 获取trans类型对象的成员数量
tuple_elements<1, trans>::type cnt = get<1>(someVal); // cnt与someVal的第二个成员类型一致
tuple之间的比较必须成员数量一致,并且各成员类型一致。
2.bitset类型:
bitset使位运算更加方便,能够处理超过最长整形类型大小的位集合。
bitset<32> bitvec(1U); // 32位,低位为1,其他位为0
编号从0开始的二进制位被称为低位,编号到31结束的二进制位被称为高位。
当用整型来初始化bitset时,整型会转换成unsigned long long 。bitset的位大于unsigned long long时,剩余高位被置0,。bitset的位小于unsigned long long时,超出bitset的高位部分被丢弃。
bitset<n> b(str, pos, m, zero, one); // 从str的pos位拷贝m个字符到b中
str:字符串 pos:str的第pos位,默认0 m:截取m个
zero:遇到该字符转换成b中的0,默认’0’ one:遇到该字符转成1,默认‘1’
str只能包涵zero和one,否则抛出invalid_argument异常。
3.正则表达式:
一种描述字符序列的方法,是极其强大的计算工具。新标准库的一部分,RE库定义在头文件regex中。
regex使用的正则表达式语言是ECMAScript。
string strPattern = "[[:alpha:]][^c]ei[[:alpha:]]"; // 模式[[:alpha:]]匹配任何字符,非c后接ei
regex r(strPattern); // 构造一个用于查找模式的regex
smatch ret; // 用于保存查找结果
string strTest = "receipt friend theif"; // 测试字符串
bool IsFind = regex_search(strTest, ret, r); // 是否有匹配的字符串
regex_search是查找是否有匹配的子字符串,regex_match是是否匹配。还有一个没有参数ret的版本。
最后一个参数是可选regex_constants::match_flat_type的值。
regex r(re, f);
re可以是正则表达式,string,表示范围的迭代器等。
f指出对象如何处理标识,默认是ECMAScript。
一个正则表达式的语法是否正确是在运行时解析的。
正则表达式编译是一个很慢的过程,因此应该尽量避免构造和赋予操作。
RE为这些不同的输入序列类型都定义了对应的类型:
// 遍历迭代器b到e,it定位到第一个匹配的位置,++操作表示找到下一个匹配位置
sregex_iterator it(b, e, r);
子表达式是模式的一部分,本身也具有意义,正则表达式语法通常用括号表示子表达式。
如果pattern有n个子表达式,则smatch会有n+1个ssub_match元素。位置[0]表示整个匹配,位置[1]到[n]表示每个对应的子表达式。
regex_replace在输入序列中查找并替换一个正则表达式。
string fmt="$2.$5.$7" //$后跟子表达式的索引号来表示一个特定的子表达式
regex r(phone);
string num = "(908) 555-1800"
regex_replace(num, r, fmt);
4.随机数:
随机数引擎类生成随机unsigned整数序列。
随机数分布类使用引擎返回服从特定概率分布的随机数。
default_random_engine e; // 生成随机无符号数
cout<<e();
标准库定义了多个随机数引擎类,区别在于性能和随机性质不同。每个编译器都会指定其中一个作为default_random_engine类型。
大多数场合随机数引擎的输出是不能直接使用的。因为生成的值范围通常与需要的不符。
uniform_int_distribution<unsigned> u(0, 9); cout <<u(e);
uniform_int_distribution类型生成均匀分布的unsigned值。
随机数发生器:指分布对象和引擎对象的组合。
一个给定的随机数发生器一直会生成相同的随机数序列。
一个函数如果定义了局部的随机数发生器,应该将其(包括引擎和分布对象)定义为static的。因为static会在函数调用之间保持住状态。否则每次调用函数都会产生相同的序列。
种子:为了达到每次运行都产生不同的随机结果的目的,可以提供一个种子,种子就是一个数值。引擎可以利用它从序列中的一个新位置重新开始生成随机数。
- 创建引擎对象时提供种子:default_random_engine e(3214);
- 调用引擎的seed成员:e.seed(3453);
没有设置种子使用默认种子,种子一样时,生成的序列也一样。
可以选择调用系统函数time, 它返回从特定时刻到当前经历多少秒。如果是一个周期循环的函数,使用这个函数可能就无效了。
uniform_real_distribution类型可以生成随机浮点数。
uniform_int_distribution<double> u(0,1); u(e); // 0到1的均匀分布的随机浮点数
正态分布的随机数使用normal_distribution。
normal_distribution<> n(4, 1.5); // 使用默认模板参数,4是均值,1.5是标准差
bernnoulli_distribution b(.55); //返回一个bool类型,概率是55/45,默认概率是50/50
5.IO库再探:
除了条件状态外,每个iosteam对象还维护一个格式状态。来控制io如何格式化的细节。格式状态控制格式化的某些方面如整型值是几进制,浮点值的精度,一个输出元素的宽度等。
操纵符:标准库定义了一组操纵符来修改流的格式状态。一个操纵符是一个函数或是一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入或输出运算符操纵符也返回它所处理的流对象。因此我们可以在一条语句中组合操纵符合数据。
操纵符用于两大类输出控制:控制数值的输出形式,以及控制补白的数量和位置。
大多数改变格式状态的操纵符,都是设置/复原成对的。一个用来将格式状态设置为一个新值,另一个用来将其复原为默认格式。
cout <<true <<" "<<false <<"changed:"<<boolalpha <<true <<" "<<false;
输出结果: 1 0changed:true false 后面再加<<noboolalpha 将流恢复到初始状态
操纵符hex、oct和dec将其改为十六进制、八进制或是改回十进制(只影响整型)。
showbase操纵符:在输出结果中显示进制。恢复用noshowbase。
uppercase操纵符:输出大写的0X,以及十六进制a~f以大写输出。
默认情况,浮点数按六位数字精度打印。可以通过调用io对象的precision成员或使用precision操纵符来改变精度。
cout<<cout.precition(8)<<setprecition(12); // 精度6->8->12
endl和flush也是操纵符。
默认情况下,输入运算符会忽略空白符(空格符,制表符,换行符,换纸符和回车符)。
操纵符noskipws会令输入运算符读取空白符。
未格式化IO:这些操作允许我们将一个留当作一个无解释的字节序列来处理。
is.get(ch) 从is读取下一个字节存入字符ch中,返回is
os.put(ch) 将字符ch输出到os,返回os
is.get() 将is的下一个自己作为int返回
is.putback(ch) 将字符ch放回is,返回is
is.unget() 将is向后移动一个字节,返回is
is.peek() 将下一个字节作为int返回,但不从流中删除它函数
peek和无参的get版本都已int类型从输入流返回一个字符。返回int的函数将他们要返回的字符先转化成unsigned char,然后再将结果提升到int。所以返回的int是正值,而标准库使用负值表示文件尾。
头文件cstdio定义了一个名为EOF的const,可以用它来检测从get返回的值是否是文件尾。
也可以从流中读取多个字节(其他版本的get以及write,getline)。
标准库为所有流类型都定义了seek和tell函数。绑定到cin,cout等流时,操作会将流置于一个无效状态。由于stream和ostream类型通常不支持随机访问。所以只适用于fstream和sstream。
输入和输出版本的差别在于名字的后缀是g(get输入流使用)还是p(put输出流使用)