typedef decltype(item) trans; // 获取成员数量 size_t sz = tuple_size(trans)::value; // cnt和item中的第二个成员类型相同 tuple_element<1, trans>::type cnt = get<1>(item);
头文件:bitset
原型 | 说明 | 说明2 | 样例 |
---|---|---|---|
bitset |
n位,每一位均为0 | constexpr | |
bitset |
unsigned long long低n位的拷贝 | constexpr | |
bitset |
从pos开始m个字符的拷贝。0和1的字符支持自定义 | ||
bitset |
和上一个一样,换成char* |
置位:x位变成1
复位:x位变成0
原型 | 说明 |
---|---|
b.any() | 是否存在置位 |
b.all() | 是否所有位都置位 |
b.none() | 不存在置位? |
b.count() | 置位的位数 |
b.size() | constexpr,返回位数 |
b.test(pos) | 如果pos是置位的则为true,否则为false |
b.set(pos, v) | 设置。v默认为true |
b.set() | 将b中所有位置位 |
b.reset(pos) | pos位置复位 |
b.reset() | 所有位复位 |
b.flip(pos) | 反转pos位 |
~b[pos] | 和上一个等价 |
b.flip() | 反转所有位 |
b[pos] | 如果b是const,则返回bool |
b.to_ulong() | 拼成unsigned long。如果放不下,抛出overflow_error异常 |
b.to_ullong() | 同上,拼成unsined long long |
b.to_string(zero, one) | 拼成string。zero和one默认为'0'和'1' |
os << b | 打印0和1的字符串 |
is >> b | 当下一位不是0或1,或者已经读满时,读取停止 |
头文件:regex
默认情况下regex的正则语言是:ECMAScript(ECMA-262规范)
这俩接口的参数是一样的:
(seq, m, r, mft)
(seq, r, mft)seq: 匹配串
r: 正则串,regex对象
m:match容器,用于存储结果
mft:匹配参数,详细见后
定义在regex和regex_constants::syntax_option_type中
smatch会存储n+1个结果(n表示表达式的数量),第0个表示整个匹配,后面跟上每个子表达式的结果。
如果正则表达式错了,会抛出regex_error
错误
*、?、+或{
之前没有有效的正则表达式example:
string search_s("receipt freind theif receive"); string pattern("[^c]ei"); pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*"; regex r(pattern, regex::icase); for (sregex_iterator it(search_s.begin(), search_s.end(), r), end_it; it != end_it; ++it) { cout << it->str() << endl; } /* 输出结果: freind receive */
using std::regex_constants::format_default; string fmt = "$2.$5.$7"; regex r(phone), string num = "(908)555-1800"; cout << regex_replace(num, r, fmt, format_default) << endl; // 输出:908.555.1800
因为rand库存在局限性,所以c++程序员应该使用default_random_engine
类和恰当的分布类对象
随机数发生器:分布对象和引擎对象的组合
一般使用方式:
uniform_real_distribution<double> u(0, 1); //分布类一般为xxx_distribution,详细数据搜索相关文档 default_random_engine e; //引擎类一般为xxx_engine,详细数据搜索相关文档 cout << u(e) << endl;
用于控制IO如何格式化的细节,如果整型值是几进制、浮点数的精度、输出元素的宽度等
注: 当操作符改变流的格式状态时,通常改变后的状态对所有后续IO都生效。因此要注意及时还原
//控制布尔值的格式 cout << true << " " << false << endl << boolalpha << true << " " << false << endl; /* 预期结果: 1 0 true false */
前面带(*)
的表示默认状态
这些方法只控制下一个输出的状态,不改变输出流
单字节处理:
多字节处理:
只支持fstream和sstream
下列操作g
表示输入流,p
表示输出流
读取文件样例:
ifstream oFile; oFile.open("xxx", ios::in | ios::binary); if (oFile) { oFile.seekg(0, oFile.end); size_t iSize = oFile.tellg(); char* sink = new char[iSize + 1]; oFile.seekg(0, oFile.beg); oFile.read(sink, iSize); oFile.close(); }
处理构造函数初始值异常的唯一方法是将构造函数写成函数try语句块
template <typename T> Blob<T>::Blob(std::initializer_list<T> il) try: data(std::make_shared<std::vector<T>>(il)) { //空函数体 } catch(const std::bad_alloc &e) { handle_out_of_memory(e); }
inline namespace PersonCode { void func1(); } namespace PersonCode { // 隐式内联 void func2(); } namespace PersonCode2 { void func3(); } // 另一个文件 namespace MainCode{ #include "PersonCode.h" #include "PersonCode2.h" } MainCode::func1(); // 可以直接使用 MainCode::func2(); MainCode::PersonCode2::func3(); // 需要一层层申明
仅在特定的文件内部有效,其作用范围不会横跨多个不同的文件。
如果两个文件都含有未命名的命名空间,则这两个空间互相无关。
一个命名空间可以有好几个同义词或别名,所有别名都与命名空间原来的名字等价。
namespace person = PersonCode;
有时会用在不同库指针或引用直接交互的情况
// base含有虚函数,Derived是base的公有派生类 if (Derived *dp = dynamic_cast<Derived*>(bp)) { // 使用dp指向的Derived对象 } else { // 使用bp指向的base对象 }
void f(const base &b) { try { const &d = dynamic_cast<const Derived&>(b); // 使用b引用的Derived对象 } catch (std::bad_cast) { // 处理转换失败的情况 } }
用来动态判断类型的函数。
当typeid作用于指针时(而非指针所指的对象),返回的结果是该指针的静态编译时的类型
Derived* dp = new Derived(); Base* bp = dp; cout << boolalpha; if (typeid(*bp) == typeid(*dp)) { cout << "test1: " << true << endl; } if (typeid(*bp) == typeid(Derived)) { cout << "test2: " << true << endl; } cout << false << endl; // 运行结果: false
返回值类型:type_info
typeid(Derived).name(); // 输出类型名,具体输出内容依赖编辑器 typeid(Derived).before(typeid(Base)); //判断前后顺序,顺序关系依赖于编辑器
bool operator== (const Base &lhs, const Base &rhs) { return typeid(lhs) == typeid(rhs) && lhs.equal(rhs); }
这个写法的优点:
有两种:限定作用域的和不限定作用域的
不限定作用域的可以隐式转化成int,限定作用域的不可以,所以作为库的对外接口时,不能用enum class。
C++11可以【设置潜在类型】和【提前声明enum】
默认类型是int
enum intValues : unsigned long long { long_type = 111111111111111111111111ULL, }
enum intValues : unsigned long long;
可以在类的外部定义指向数据成员和函数成员的指针
class Math { public: int x, y; Math() = default; Math(int x1, int y1) : x(x1), y(y1) {}; int GetY() { return y; } int SetAndGetY(int y2) { this->y = y2; return this->y; } bool SetXY(int x1, int y1) { x = x1; y = y1; return true; } private: int z = 6; int GetZ() { return z; } }; int main() { Math obj(1, 2); const int Math::*p = &Math::x; cout << obj.*p << endl; auto pmf = &Math::GetY; cout << (obj.*pmf)() << endl; int (Math:: * pmf2)(int); pmf2 = &Math::SetAndGetY; cout << (obj.*pmf2)(6) << endl; cout << (obj.*pmf)() << endl; using SetXY = bool (Math::*)(int x1, int y1); SetXY set_xy = &Math::SetXY; cout << boolalpha << (obj.*set_xy)(1, 2) << endl; // 不可以改成obj.*set_xy(1, 2) }
因为函数调用运算符的优先级较高,所以在声明指向成员函数的指针并使用这样的指针进行函数调用时,括号必不可少: (obj.*set_xy)(1, 2)
联合是一种特殊的类,一种节省空间的类。
union可以定义包含构造函数和析构函数在内的成员函数。但是因为它既不能继承其他类,也不能作为基类使用,所以union中不能含有虚函数。
union { char cval; int ival; };
匿名union不能包含private和protect,也不能定义成员函数
匿名的union在该作用域内可以直接访问成员,因此常用于管理类中的成员
局部类的所有成员(包括函数)都必须完整定义在类的内部。因此局部类和嵌套类的作用还是差的很远。
局部类只能访问外层作用域定义的类型名、静态变量以及枚举成员。普通局部变量无法访问。
因机器而异的特性,通常换台机器就要重写。
位域在内存中的布局是与机器相关的
class File { unsigned int mode : 2; }
当对象的值可能在程序的控制或检测之外被改变时,应该将该对象声明为volatile
,告诉编辑器不应对这样的对象进行优化。
注:合成的拷贝/移动构造函数以及赋值运算符,不能用于volatile对象,除非自定义。
用于指出这是非c++函数用的语言。常用于库的接口。
在构建dll时,通常还会带上_declspec(dllexport)
声明导出函数、类、对象。
尤其是函数指针,有没有指示是不同的
void (*pf1)(int); // 指向一个c++函数 #ifdef __cplusplus // 兼容c和c++编译同一个源文件 extern "C" void (*pf2)(int); // 指向一个c函数 #endif pf1 = pf2; // 错误:类型不同