C++ 学习笔记之(17)-标准库特殊设施(tuple类型、bitset类型、正则表达式、随机数以及IO库再探)
标准库内容巨大,故仅介绍某些标准库设施:tuple
、bitset
、正则表达式以及随机数,此外还有一些IO
库功能:格式控制、未初始化IO
和随机访问
tuple
类型
tuple
类似与pair
,但pair
只有两个成员,tuple
却有任意数量的成员
定义和初始化tuple
- 标准库函数
make_tuple
类似于make_pair
函数,用来生成tuple
对象 - 使用标准库函数模板
get
访问tuple
成员 - 可使用
tuple_size
或tuple_element
辅助类查询tuple
的数量和类型 tuple
定义了<
、==
运算符,故可将tuple
序列传递给算法,并在无序容器中将tuple
作为关键字类型
tuple<size_t, size_t, size_t> threeD; // 三个成员都设置为 0. 调用默认构造函数,执行值初始化
tuple<size_t, size_t, size_t> threeD = {1, 2, 3}; // 错误,因为该构造函数为 explicit
tuple<size_t, size_t, size_t> threeD{1, 2, 3}; // 正确:explicit 构造函数只能执行直接初始化
auto item = make_tuple("0-999", 3, 20.00); // tuple<const char *, int , double>
auto book = get<0>(item); // 返回 item 的第一个成员
typdef decltype(item) trans; // trans 是 item 的类型
size_t sz = tuple_size<trans>::value; // 返回 trans 类型对象中成员的数量, 3
tuple_element<1, trans>::type cnt = get<1>(item); //cnt 的类型与 item 中第二个成员相同,为 int
tuple
可用作从函数的返回值
bitset
类型
bitset
可使得位运算更为简便,且能够处理超过最长整形类型大小的位的集合
定义和初始化bitset
bitset
中的二进制位未命名,可通过位置访问。从0
开始编号的二进制位为 低位, 编号到31
结束的二进制位为 高位
下图为bitset
构造函数
* 整型值初始化bitset
时,值将转换为unsigned long long
类型,并被当做位模式处理。若bitset
的大小小于一个unsigned long long
中的二进制位数, 则超出bitset
大小的高位被丢弃。 否则,剩余的高位置为0
c++
// bitvec1 比 初始值小;初始值中的高位被丢弃
bitset<13> bitvec1(0xbeef); // 二进制位序列为 1111011101111
// bitvec2 比初始值大,它的高位被置为0
bitset<20> bitvec2(0xbeef); // 二进制位序列为 0000 1011 1110 1110 1111
使用字符串初始化
bitset
时,下标最小的字符对应高位string str("1001001100"); bitset<8> bitvec5(str, 5, 4); // 从 str[5]开始的四个二进制位, 0110, 结果为 00000110
bitset
操作
bitset<32> bitvec(1U); // 32位,低位为1, 剩余位为0
quizA |= 1UL << 27; // 将第27位置1
quizA &= ~(1UL << 27); // 将第27为置0
正则表达式
暂时未整理此部分内容,详情请查阅
- regex
- C++ primer P645
随机数
- 随机数引擎(random-number engines):生成
unsigned
随机数序列 - 随机数分布类(random-number distribution):使用引擎类生成指定类型的、在给定范围内的、服从特定概率分布的随机数
- C++程序不应该使用库函数
rand
, 而应使用default_random_engine
类和恰当的分布类对象
随机数引擎和分布
随机数引擎为函数对象类,定义了函数调用运算符,不接受参数并返回一个随机unsigned
整数
- 随机数发生器:指分布对象和引擎对象的组合
default_random_engine e; // 生成随机无符号数,原始随机数
for(size_t i = 0; i < 10; ++i)
cout << e() << " "; // 调用 e() 对象生成下一个随机数, 范围为[0, unsigned 最大值]
uniform_int_distribution<unsigned> u(0, 9); // 均匀分布的随机数, [0, 9]
for(size_t i = 0; i < 10; ++i)
cout << u(e) << " "; // u 作为随机数源, 生成均匀分布的随机数
- 一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将其(包括引擎和分布对象)定义为
static
的,否则,每次调用函数都会生成相同的序列。 - 可通过随机数种子生成不同的随机结果, 一般使用系统函数
time
其他随机数分布
* uniform_real_distribution
: 随机浮点数,默认为double
类型
* bernoulli_distributiion
:类,非模板,返回bool
值,概率为0.5
, 概率可调整
* 新标准库可生成非均匀分布的随机数,定义了20
种分布类型
IO
库再探
格式化输入与输出
iostream
对象不仅包含条件状态,还维护一个格式状态控制格式化细节
- 操纵符(manipulator):修改流的格式状态, 比如
endl
- 操纵符用于控制数值的输出形式以及控制补白的数量和位置
- 当操纵符改变流的格式状态时,通常改变后的状态对所有后续
IO
都生效 - 操纵符
hex
、oct
和dec
只影响整形运算对象,浮点值的表示形式不受影响
- 定义在
iomanip
中的操纵符
- 默认情况下,输入运算符会忽略空白符(空格符、制表符、换行符、换纸符和回车符),可使用操纵符
noskipws
令输入运算符读取空白符
未格式化的输入/输出操作
标准库提供了一组低层操作,支持 未格式化IO,即允许将流当做一个无解释的字节序列处理
* 将字符放回输入流:有时需要读取一个字符才能知道还未准备好处理它,此时需要放回流中
peek
:返回输入流下一个字符的副本,但不会将它从流中删除,peek
返回的值仍留在流中unget
:使输入流向后移动,从而最后读取的值又回到流中。即使不知道从流中读取什么值,也可调用putback
:特殊版本的unget
,退回从流中读取的最后一个值,接受一个参数,此参数与最后读取的值相同输入操作返回
int
值:可以返回文件尾标记,用来表示文件尾一些未格式化
IO
操作一次处理大块数据,要求自己分配并管理用来保存和提取数据的字符数组
流随机访问
随机
IO
本质上依赖于系统,需查询系统文档istream
和ostream
类型不支持随机访问, 故seek
和tell
函数只适用于fstream
和sstream
类型
- 标准库虽然区分
seek
函数和tell
函数的放置和获得,但在流中只维护单一的标记
结语
本文介绍了特殊的IO
操作和四个标准库类型:tuple
、bitset
、正则表达式和随机数。库的更多使用可参阅