17.1 tuple类型
tuple是一个类似pair的模板。每一个pair类型有2个不同类型的成员。一个tuple同样有不同类型的成员,但是它可以有任意数量的成员。tuple类型定义在tuple头文件。
注解
tuple可以认为是一个“快捷且脏”的数据结构。
17.1.1 定义和初始化tuple
当我们定义一个tuple,需要指定每个成员的类型:
1
2
3
|
tuple<size_t, size_t, size_t> threeD; // all three members set to 0
tuple<string, vector<double>, int, list<int>>
someVal("constants", {3.14, 2.718}, 42, {0,1,2,3,4,5});
|
tuple默认构造函数值初始化每一个成员。tuple构造函数是explicit的,因此必须使用直接初始化语法:
1
2
|
tuple<size_t, size_t, size_t> threeD = {1,2,3}; // error
tuple<size_t, size_t, size_t> threeD{1,2,3}; // ok
|
类似于make_pair函数,标准库定义了一个make_tuple函数生成tuple对象:
1
2
|
// tuple that represents a bookstore transaction: ISBN, count, price per book
auto item = make_tuple("0-999-78345-X", 3, 20.00);
|
和make_pair一样,make_tuple函数使用其参数的类型推导tuple的类型。上面这个例子种,item类型为tupple<const char*, int, double>。
访问tuple成员
tuple的成员是未命名的,我们通过一个标准库函数模板get访问其成员。为了使用get我们必须指定一个显式模板实参,这个实参是我们想要访问的成员的位置。传递tuple对象给get,get返回指定成员的引用:
1
2
3
4
|
auto book = get<0>(item); // returns the first member of item
auto cnt = get<1>(item); // returns the second member of item
auto price = get<2>(item)/cnt; // returns the last member of item
get<2>(item) *= 0.8; // apply 20% discount
|
尖括号<>中的值必须是整形常量表达式。
如果不知道tuple的类型,我们可以使用2个辅助的类模板找出tuple成员的数量和类型:
1
2
3
4
5
|
typedef decltype(item) trans; // trans is the type of item
// returns the number of members in object's of type trans
size_t sz = tuple_size<trans>::value; // returns 3
// cnt has the same type as the second member in item
tuple_element<1, trans>::type cnt = get<1>(item); // cnt is an int
|
为了使用tuple_size或tuple_element,我们需要直到tuple对象的类型。通常最简单的确定对象类型的方法是使用decltype。
tuple_size有一个公开的静态数据成员value,表示指定tuple成员的数量。tuple_element有一个公开成员type表示指定成员的类型。
关系和相等操作符
只有当2个tuple有相同数量的成员时,才能进行比较。为使用==操作符,tuple之间的每一对成员必须可以使用==操作符。关系操作符同样的规则。
1
2
3
4
5
6
7
|
tuple<string, string> duo("1", "2");
tuple<size_t, size_t> twoD(1, 2);
bool b = (duo == twoD); // error: can't compare a size_t and a string
tuple<size_t, size_t, size_t> threeD(1, 2, 3);
b = (twoD < threeD); // error: differing number of members
tuple<size_t, size_t> origin(0, 0);
b = (origin < twoD); // ok: b is true
|
注解
因为tuple定义<和==操作符,我们可以将tuple的元素传递给标准库算法,也可以将tuple作为ordered容器的键。
17.1.2 使用tuple返回多个值
tuple的一个常见应用是从一个函数返回多个值。
返回tuple的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// matches has three members: an index of a store and iterators into that store's vector
typedef tuple<vector<Sales_data>::size_type,
vector<Sales_data>::const_iterator,
vector<Sales_data>::const_iterator> matches;
// files holds the transactions for every store
// findBook returns a vector with an entry for each store that sold the given book
vector<matches>
findBook(const vector<vector<Sales_data>> &files, const string &book)
{
vector<matches> ret; // initially empty
// for each store find the range of matching books, if any
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
// find the range of Sales_data that have the same ISBN
auto found = equal_range(it->cbegin(), it->cend(),
book, compareIsbn);
if (found.first != found.second) // this store had sales
// remember the index of this store and the matching range
ret.push_back(make_tuple(it - files.cbegin(),
found.first,
found.second));
}
return ret; // empty if no matches found
}
|
使用函数返回的tuple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void reportResults(istream &in, ostream &os,
const vector<vector<Sales_data>> &files)
{
string s; // book to look for
while (in >> s) {
auto trans = findBook(files, s); // stores that sold this book
if (trans.empty()) {
cout << s << " not found in any stores" << endl;
continue; // get the next book to look for
}
for (const auto &store : trans) // for every store with a sale
// get<n> returns the specified member from the tuple in store
os << "store " << get<0>(store) << " sales: "
<< accumulate(get<1>(store), get<2>(store), Sales_data(s))
<< endl;
}
}
|
17.2 bitset类型
bitset类型定义在bitset头文件
17.2.1 定义和初始化bitset
bitset类是一个类模板,和array类一样,拥有固定长度。当定义bitset对象时,需要指定bitset将要包含的位数:
1
|
bitset<32> bitvec(1U); // 32 bits; low-order bit is 1, remaining bits are 0
|
bitset中的位通过位置访问。
用unsigned值初始化bitset
当使用一个整型值初始化一个bitset时,值被转化为unsigned long long的位模式。如果bitset大小比unsigned long long大,则剩下的高位置为0,否则超出bitset大小的高位被丢弃。
1
2
3
4
5
6
|
// bitvec1 is smaller than the initializer; high-order bits from the initializer are discarded
bitset<13> bitvec1 (0xbeef); // bits are 1111011101111
// bitvec2 is larger than the initializer; high-order bits in bitvec2 are set to zero
bitset<20> bitvec2(0xbeef); // bits are 00001011111011101111
// on machines with 64-bit long long 0ULL is 64 bits of 0, so ~0ULL is 64 ones
bitset<128> bitvec3(~0ULL); // bits 0 ... 63 are one; 63 ... 127 are zero
|
用字符串初始化bitset
可以使用string或指向字符数组的指针初始化bitset。任一种情况,字符直接表示位模式。
1
|
bitset<32> bitvec4("1100"); // bits 2 and 3 are 1, all others are 0
|
如果字符串包含少于bitset大小的字符,则高位置为0。
注解
string和bitset的下标是相反关联的:string最右边的字符用来初始化bitset最低位。
可以使用子字符串初始化bitset:
1
2
3
|
string str("1111111000000011001101");
bitset<32> bitvec5(str, 5, 4); // four bits starting at str[5], 1100
bitset<32> bitvec6(str, str.size()-4); // use last four characters
|
bitset操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
bitset<32> bitvec(1U); // 32 bits; low-order bit is 1, remaining bits are 0
bool is_set = bitvec.any(); // true, one bit is set
bool is_not_set = bitvec.none(); // false, one bit is set
bool all_set = bitvec.all(); // false, only one bit is set
size_t onBits = bitvec.count(); // returns 1
size_t sz = bitvec.size(); // returns 32
bitvec.flip(); // reverses the value of all the bits in bitvec
bitvec.reset(); // sets all the bits to 0
bitvec.set(); // sets all the bits to 1
bitvec.flip(0); // reverses the value of the first bit
bitvec.set(bitvec.size() - 1); // turns on the last bit
bitvec.set(0, 0); // turns off the first bit
bitvec.reset(i); // turns off the ith bit
bitvec.test(0); // returns false because the first bit is off
bitvec[0] = 0; // turn off the bit at position 0
bitvec[31] = bitvec[0]; // set the last bit to the same value as the first bit
bitvec[0].flip(); // flip the value of the bit at position 0
~bitvec[0]; // equivalent operation; flips the bit at position 0
bool b = bitvec[0]; // convert the value of bitvec[0] to bool
|
#### 获取bitset的值
to_ulong和to_ullong操作返回和bitset对象同样位模式的数值。只有在bitset大小小于或等于unsigned long或unsigned long long类型时才可用:
1
|
unsigned long ulong = bitvec3.to_ulong();
|
注解
如果bitset不能放进指定类型,这2个操作抛出overflow_error异常。
bitset IO操作
输入操作符从输入流读取字符到一个临时string对象,直到读满bitset大小或遇到一个不是0或1的字符,或者遇到输入操作。然后bitset由这个临时string初始化。输出操作符打印bitset对象的位模式。
1
2
3
|
bitset<16> bits;
cin >> bits; // read up to 16 1 or 0 characters from cin
cout << "bits: " << bits << endl; // print what we just read
|
使用bitset
1
2
3
4
5
6
7
8
9
10
11
|
bool status;
// version using bitwise operators
unsigned long quizA = 0; // this value is used as a collection of bits
quizA |= 1UL << 27; // indicate student number 27 passed
status = quizA & (1UL << 27); // check how student number 27 did
quizA &= ~(1UL << 27); // student number 27 failed
// equivalent actions using the bitset library
bitset<30> quizB; // allocate one bit per student; all bits initialized to 0
quizB.set(27); // indicate student number 27 passed
status = quizB[27]; // check how student number 27 did
quizB.reset(27); // student number 27 failed
|
17.3 正则表达式
正则表达式是描述一串字符的一种方式。RE库定义在regex头文件,是新库的一部分。
类 |
说明 |
regex |
正则表达式类 |
regex_match |
根据正则表达式匹配字符串 |
regex_search |
查找第一个匹配正则表达式的子串 |
regex_replace |
使用指定的格式替换正则表达式 |
sregex_iterator |
迭代器适配器,调用regex_search遍历字符串中匹配项 |
smatch |
容器类,包含查找的结果集 |
ssub_match |
匹配子表达式的结果集 |
regex类表示一个正则表达式。除了初始化和赋值,regex没有什么操作。函数regex_match和regex_search确定给定的字符串是否匹配指定的regex。如果整个字符串匹配正则表达式,regex_match返回true。如果有子串匹配,则regex_search返回true。还有一个regex_replace函数。
regex_match和regex_search的参数
(seq, m, r, mft)
(seq, r, mft)
使用正则表达式库