std::tuple
tuple 可以将一些数据组合成单一对象.
构造函数是explicit 的
std::tuple<int,double> s = {
1,2.5};//错误
std::tuple<int,double> s(1,2.5);//正确
访问成员
std::tuple<int,double> s(1,2.4);
std::get<0>(s);//获取s的第一个元素
std::get<1>(s);//获取s的第二个元素,以此类推
std::get返回的是一个引用,因此可以直接利用该函数修改tuple元素的值
std::tuple<int,double> s(1,2.4);
std::get<0>(s)*=20;
std::cout << std::get<0>(s) << std::endl;//输出20
获取tuple 的数量和类型
auto s;//假设s是一个不知道数量和类型的tuple
typedef decltype(s) trans;
auto sz = std::tuple_size<trans>::value;//获得了未知tuple的数量
std::tuple_element<1,trans>::type cnt = std::get<1>(s);//第一个元素的类型
两个tuple 只有数量,类型一致时才能进行比较, 并且每个成员的==运算符和<运算符必须合法
std::bitset
初始化的方式
#include<bitset>
void init()
{
std::bitset<32> b1(1U);
std::bitset<4> b2(0xf);//1111
std::bitset<2> b3(0xf);// 11 ,高位多余的部分被丢弃
std::bitset<32> b4(~0ULL);// long long 0ULL是64个0比特,因此~0ULL 是64个 1
std::bitset<32> b5("1100");
std::string s = "11001100";
std::bitset<32> b6(s,4,4);//1100
std::cout << b6.to_string() << std::endl;
std::bitset<32> b7(s, s.size()-4);//取最后四位 1100
}
一些操作
void test()
{
std::bitset<4> s1("1111");
std::cout << s1.to_string() << std::endl;//输出1111
std::cout << s1.all() << std::endl;//判断s1是否所有位都置位,也就是设为1
std::bitset<4> s2("1000");
std::cout << s2[0] << std::endl;//返回0,默认低位是从最右边开始
std::cout << s2.any() << std::endl;//判断s2是否含有1
std::bitset<4> s3("0000");
std::cout << s3.none() << std::endl;//判断s3是否全部没有置位
std::cout << s3.count() << std::endl;//统计s3中1的个数
std::cout << s3.size() << std::endl;//统计s3的size
std::cout << s3.test(0) << std::endl;//s3第0位为1返回true,否则返回false
s1.reset();//将s1所有位设置为0, s1从"1111"变为 "0000"
std::bitset<4> s4("1101");
s4.reset(0);//将s4第0位设为0, 输出1100
s3.set(); //将s3所有位设置为1, s3变成 1111
s3.set(1,false); //将s3第1位设置为0, s3 变成 1101
s3.flip();//将s3每一位改变状态,也就是每一位原来是1的变成0,原来是0的变成1
s3.flip(2);//将s3的第2位改变状态
std::cin >> s3; //读取0或者1,当下一个字符不是0或者1,或者已经读完b.size时,结束
std::cout << s3 << std::endl; //直接输出
std::bitset<4> s5("0010");
std::cout << s5.to_ullong() << std::endl;//输出 2
}
正则表达式
int test()
{
std::string pattern("[^c]ei");
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
std::regex r(pattern);
std::smatch results;
std::string teststr("receive freind teind");
if(std::regex_search(teststr,results, r))
std::cout << results.str() << std::endl;
}
regex默认使用的正则表达式语言是ECMAScript,可以设置为其他的方式
std::regex r2(pattern, std::regex_constants::icase);//匹配时忽略大小写
std::regex r3(pattern, std::regex_constants::nosubs);//不保存匹配的子表达式
std::regex r4(pattern, std::regex_constants::optimize);//执行速度优于构造速度
std::regex r5(pattern, std::regex_constants::basic);//使用POSIX基本的正则表达式语法
std::regex r6(pattern, std::regex_constants::extended);//使用POSIX版扩展的正则表达式语法
std::regex r7(pattern, std::regex_constants::awk);//使用POSIX版本的 awk语法
std::regex r8(pattern, std::regex_constants::grep);//使用POSIX版本的 grep 语法
std::regex r9(pattern, std::regex_constants::egrep);//使用POSIX版本的 egrep 语法
正则表达式可以被看成用简单程序设计语言编写的"程序". 如果编写的正则表达式有错误,只有在运行中才会报错,可以用try catch 捕获
try{
std::regex r("[[:alum:]+\\.(cpp|cxx|cc)$", std::regex_constants::icase);
}catch(std::regex_error e)
{
std::cout << e.what() << "\n code:" << e.code() << std::endl;//错误代码
}
匹配结果被传入了一个类型为std::smatch的对象中.
这里std::smatch 与输入序列存在一定的对应关系.输入string, 匹配结果为std::smatch, 如果输入一个const char*, 则匹配结果不再是std::smatch 类型,而是std::cmatch
输入序列 使用的正则表达式类
string regex, smatch, ssub_match, sregex_iterator
const char * regex, cmatch, csub_match, cregex_iterator
wstring wregex, wsmatch, wssub_match, wsregex_iterator
const wchar_t* wregex, wcmatch, wcsub_match, wcregex_iterator
POSIX 匹配字符集
[:alnum:] 文字数字字符
[:alpha:] 文字字符
[:digit:] 数字字符
[:graph:] 非空字符(非空格、控制字符)
[:lower:] 小写字符
[:cntrl:] 控制字符
[:print:] 非空字符(包括空格)
[:punct:] 标点符号
[:space:] 所有空白字符(新行,空格,制表符)
[:upper:] 大写字符
[:xdigit:] 十六进制数字(0-9,a-f,A-F)
//基本正则表达式(BRE)和扩展正则表 达式(ERE)
//BRE和ERE到底有什么区别?其实仅仅是元字符的不同!在BRE方式中,只承认^ 、$、 . 、[ 、] 、*这些是元字符,所有其他的字符都被识别为文字字符。而ERE中,则添加了(、 ) 、{ 、} 、?、 + |、等元字符(及其相关功能)。
void test()
{
std::string pattern = "[[:alpha:]]*[[:digit:]].[[:alpha:]]*";//匹配含有至少一个数字的单词,[[:digit:]].必须在数字正则式外面继续包围一层[].来代表至少含有一个数字
std::regex r(pattern);
std::string s{
"freind teind e2e b2b bb2bb"};
try{
for(std::sregex_iterator it(s.begin(),s.end(), r),end_it; it!=end_it;it++)
{
std::cout << "prefix:" << it->prefix() << "|suffix:" << it->suffix() << "|str:" << it->str() << std::endl;
}
}catch(std::regex_error e)
{
std::cout << e.what() << "\n code: " << e.code() << std::endl;
}
}
//该函数的输出是
prefix:freind teind|suffix:b2b bb2bb|str:e2e
prefix:|suffix: bb2bb|str:b2b
prefix: |suffix:|str:b2b
子串匹配
void submatch()
{
std::string pattern = "(\\()?(\\d)?";//捕获0或者多个括号以及0或者多个数字
std::regex r(pattern);
std::string s{
"2b b2b bb2bb"};
std::smatch result;
try{
if(std::regex_search(s,result, r)){
std::cout << result.str() << std::endl;//输出2
std::cout <<result.str(0) << std::endl;//输出2
std::cout <<result.str(1) << std::endl;//输出空,因为2b没有'('
std::cout <<result.str(2) << std::endl;//输出2
std::cout << result[0].matched << std::endl;//True
std::cout << result[1].matched << std::endl;//False
std::cout << result[2].matched << std::endl;//True
}
}catch(std::regex_error e)
{
std::cout << e.what() << "\n code: " << e.code() << std::endl;
}
}
regex_replace
void replace_test()
{
std::string pattern = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})";
std::regex r(pattern);
std::string s{
"(201)-555"};
std::string s1{
"(201) 555"};
std::string s2{
"(201).555"};
std::smatch result;
try{
std::cout << std::regex_replace(s, r, "$2.$5") << std::endl;
}catch(std::regex_error e)
{
std::cout << e.what() << "\n code: " << e.code() << std::endl;
}
}
可以用std::regex_constants::match_flag_type中的变量格式化匹配标志
随机数
void randtest()
{
std::default_random_engine e;//使用默认的随机数种子
std::default_random_engine e1(214756);//使用给定的种子
std::default_random_engine e2;
e2.seed(32767);//调用seed函数生成新的种子
std::default_random_engine e3(std::time(0));//time返回以秒计的时间,因此这种方式只适合生成种子间隔为秒及更长时间的应用
for(size_t i = 0; i < 10; i++)
{
std::cout << e() << std::endl;// 原始随机数
}
std::uniform_int_distribution<unsigned> u(0,9); //均匀分布
for(size_t i = 0; i < 10; i++)
{
std::cout << u(e) << std::endl;
}
std::uniform_real_distribution<double> u2(0,1);//随机实数
for(size_t i = 0; i < 10; i++)
{
std::cout << u2(e) << std::endl;
}
std::uniform_real_distribution<> u3(0,1);//使用默认的模板类型参数 double
std::normal_distribution<> u4(4,1.5);//生成正太分布的随机数
for(size_t i = 0; i < 10; i++)
{
std::cout << u4(e) << std::endl;
}
std::bernoulli_distribution u5;//这个不是个模板,是个普通类
for(size_t i = 0; i < 10; i++)
{
std::cout << u5(e) << std::endl;
}
}
格式化输入输出
void iotest()
{
bool k = true;
std::cout << k << " " << std::boolalpha << k << " " << std::noboolalpha << k << std::endl;//控制/取消布尔值输出格式
//输出不同进制数字
std::cout << "default: " << 20 << " " << 1024 << std::endl;
std::cout << "oct: " << std::oct << 20 << " " << 1024 << std::endl;
std::cout << "hex:" << std::hex << 20 << " " << 1024 << std::endl;
std::cout << "decimal: " << std::dec << 20 << " " << 1024 << std::endl;
std::cout << std::showbase;//输出数字时 会带进制标志
std::cout << "default:" << 20 << " " << 1024 << std::endl;
std::cout << "oct:" << std::oct << 20 << " " << 1024 << std::endl;//输出020 02000
std::cout << "hex:" << std::hex << 20 << " " << 1024 << std::endl;//输出0x14 0x400
std::cout << "decimal:" << std::dec << 20 << " " << 1024 << std::endl;//输出20 1024
std::cout << "Precision:" << std::cout.precision() << ", Value:" << std::sqrt(2.0) << std::endl;
std::cout.precision(12);
std::cout << "Precision:" << std::cout.precision() << ", Value:" << std::sqrt(2.0) << std::endl;
//另一种设置精度的方法
std::cout << "Precision:" << std::setprecision(14) <<std::cout.precision() << ", Value:" << std::sqrt(2.0) << std::endl;
std::cout << std::scientific << 100 * std::sqrt(2.0) << std::endl;//1E-5 这种形式
std::cout << std::fixed << 100 * std::sqrt(2.0) << std::endl;//修正后的浮点长度
std::cout << std::hexfloat << 100 *std::sqrt(2.0) << std::endl;
std::cout << std::defaultfloat << 100 * std::sqrt(2.0) << std::endl;
//打印小数点
std::cout << std::showpoint << 10.0 << std::endl;
std::cout << std::noshowpoint << 10.5 << std::endl; // 小数部分为0时不显示,非0则原样显示
//输出宽度,补充空白
int i = -16;
std::cout << "i: " << std::setw(12) << i << std::endl;
std::cout << "i: " << std::setw(12) << std::right << i << std::endl;// 默认右对齐
std::cout << "i: " << std::setw(12) << std::left << i << std::endl;
//控制输入格式
//默认会忽略空白符,可以用std::noskipws 输入读取空白符,而不是跳过他们
std::cout << std::noskipws;
}
未格式化的输入输出操作
void iotest()
{
//单字节操作
char c;
std::cin.get(c);//读入单字节
std::cout.put(c);//输出单字节
std::cout << " is print in the front of this line" << std::endl;
//unget 和putback 功能基本一致,二者都是将之前cin>>a 出去的字符,再放回cin里,这样下一个再调用cin>> b的时候,b 又和前一次读取的字符一致了.唯一差别在于 putback 可以指定字符放回cin中,unget 只能放入之前的输入(不知道之前是啥)
std::cin.putback(c);
std::cin.get(c);
std::cout << c << " is print again" << std::endl;
std::cin.putback('k');
std::cin.get(c);
std::cout << c << " is print with assigned char k" << std::endl; //指定字符k 被放入cin,调用cin 就会被输出
std::cin.unget();
std::cin.get(c);
std::cout << c << " is print with the help of unget" << std::endl;//输出单字节
//peek将下个字符返回,但是这个字符仍然在cin中. 相当于std::cin.get(k) 和 std::cin.putback(k)的结合
char l;
std::cin.putback('t');//确保cin中有值
c = std::cin.peek();
std::cin.get(l);
std::cout << "c is returned but still in cin, so l is same with c and l is " << l << " , c is " << c << std::endl;
//多字节操作
char s[1024];
std::cin.get(s, 1024, ',');//最后一个参数,当输入字符串带有这个字符时,cin读到这个字符后,就就停止继续读了,剩余的字符被放在cin中,不被写入s中
//输入abc,d
std::cout << s << std::endl; //输出abc. ",d"被留在了cin中
while(std::cin.peek() != '\n')
{
c = std::cin.get();
std::cout << "Still has char " << c << std::endl;
}
std::cin.get();//消除最后一个换行符
std::cout << "==============" << std::endl;
std::cin.getline(s,1024, ',');
std::cout << s << std::endl;//输入"abc,d",逗号会被跳过,输出abc, d还在流中
while(std::cin.peek()!='\n')//
{
c = std::cin.get();
std::cout << "Still has char " << c << std::endl;
}
std::cin.get();//消除最后一个换行符
std::cout << "==============" << std::endl;
std::cin.read(s, 5);
std::cout << s<< std::endl;//输入abcde,输出 abcde
std::cout << std::cin.gcount() << std::endl;//返回上一个未格式化读取操作从std::cin 中读取的字节数
while(std::cin.peek()!='\n')//
{
c = std::cin.get();
std::cout << "Still has char " << c << std::endl;
}
std::cin.get();//消除最后一个换行符
std::cout << "==============" << std::endl;
std::cout.write(s,3);//将s中的3个字节写入std::cout 输出abc
std::cout << "######"<< std::endl;
std::cin.ignore(3,',');//cin会读取输入,如果输入中的前3个字符不包含',', 则忽略这个三个字符.如果前3个字符中包含',',则流会跳过最先碰到的',',并停止忽略,逗号后面的字符将会留在cin 中
while(std::cin.peek() != '\n')//输入了abc1,输出了1,abc 被忽略了. 输入了"a,b",输出了b,"a,"被忽略了,b还在留在cin中
{
c = std::cin.get();
std::cout << "Still has char " << c << std::endl;
}
}
流随机访问
istream 和ostream 不支持随机访问。只有fstream 和 sstream支持
void streamTest()
{
std::ifstream is("b.txt");
std::ofstream os("a.txt");
if(!is && !os)
{
std::cout << "error" << std::endl;
}
char c;
std::cout << "current position is " << is.tellg() << std::endl;//输入流中标记的当前位置,文件存在则输出0,否则输出-1
std::cout << "current position is " << os.tellp() << std::endl;//输出流中标记的当前位置,输出0
// is.seekg(pos);//将输入流的标记重定位到给定的绝对地址。pos通常可以从tellg获得
// os.seekp(pos);//将输出流的标记重定位到给定的绝对地址。pos通常可以从tellp获得
//假定a,txt文件内容如下:第一行是ab,第二行是c
is.get(c);
std::cout << "[" << c << "] and current position is " << is.tellg() << std::endl;//输出[a] 1
char d ;
is.seekg(1,std::ios::beg);输入流中标记重定位到开始后的第一个位置
is.get(d);
std::cout << "[" << d << "] and current position is " << is.tellg() << std::endl;//输出[b] 2
char e;
is.seekg(1, std::ios::cur);//输入流从当前定位向后移一位,跳过了换行符
is.get(e);
std::cout << "[" << e << "] and current position is " << is.tellg() << std::endl;//输出[c] 4
char f;
is.seekg(-1, std::ios::cur);//输入流从当前定位向前移动一位
is.get(f);
std::cout << "[" << f << "] and current position is " << is.tellg() << std::endl;//输出[c] 4
is.seekg(0, std::ios::end);
std::cout << "current position is " << is.tellg() << std::endl;//输出5
char g;
is.seekg(-1, std::ios::end);//输入流从当前定位向前移动一位
is.get(g);//g是个换行符
std::cout << "[" << g << "]" << is.tellg() << std::endl;//输出d 4
char h;
is.seekg(-2, std::ios::end);//输入流从末尾向前移动2位, 跳过文件结束符,输出文件里最后一个字符 h
is.get(h);
std::cout << "[" << h << "]" << is.tellg() << std::endl;//输出【c】4
is.seekg(0);//直接将输入流重新定位到开头位置
std::string line;
std::getline(is,line);
std::cout << "line is [" << line << "]" << is.tellg() << std::endl;//此时流位于第一行的最末尾位置,也就是换行符所在的位置
is.seekg(-1,std::ios::cur);
char i;
is.get(i);
std::cout << "[" << i << "]" << is.tellg() << std::endl;//输出【换行符】 3
char j;
is.get(j);
std::cout << j << " " << is.tellg() << std::endl;//此时读取了第二行第一个字符[c] 4
std::cout << os.tellp() << std::endl;
os << line;
std::cout << os.tellp() << std::endl;//输出1, 因而向其中写入一行数据
os << '\n';
os << h << '\n';
}