标准库特殊设施

欢迎访问我的博客首页


1. tuple 类型


  Python 中的元组 tuple 使用小括号表示,类似 Python 的列表 list,但创建后不能修改。C++ 中的 tuple 也可以存放任意数量类型不同的成员。而且它是一个模板类型,因此初始化后的 tuple 也是不能添加、修改的。

  tuple 本身支持初始化、比较、访问操作。如果我们希望将一些数据组合成单一对象,而又不需要对它们进行复杂操作,就可以使用 tuple 而不是类或结构体,比如可以借助 tuple 返回多个值。

  下面是 tuple 的用法。在 C++ 新标准中,tuple 支持列表初始化。

// 1.1 先定义再初始化。
tuple<int, char> t1;
t1 = {1, 'c'};
// 1.2 定义时初始化。
tuple<int, char> t2(1, 'c');
// 1.3 使用 make_tuple。
tuple<int, char> t3 = make_tuple(1, 'c');
// 1.4 使用初始化列表。
tuple<int, char> t4 = {1, 'c'};
// 2. 访问。
cout << get<0>(t4) << " " << get<1>(t4) << endl;
// 3.1 已知 tuple 类型时获取元素个数(从模板参数就可以看出该类型的 tuple 有两个元素)。
size_t sz1 = tuple_size<tuple<int, char>>::value;
cout << sz1 << endl;
// 3.2 未知 tuple 类型时获取元素个数。
typedef decltype(t4) trans; // 先获取类型 trans。
size_t sz2 = tuple_size<trans>::value;
cout << sz2 << endl;
// 4. 获取下标为 1 类型未知的元素。
tuple_element<1, trans>::type cnt = get<1>(t3);
cout << cnt << endl;
// 5. 比较。
tuple<int, char> t5{1, 'b'};
cout << (t5 < t4) << endl; // true

2. bitset 类型


3. 正则表达式


3.1 匹配函数


  如果整个输入序列与表达式匹配,则regex_match函数返回true;如果输入序列中一个子串与表达式匹配,则regex_search函数返回true;如果要在输入序列中查找并替换一个正则表达式,则使用regex_replace。

1. 函数regex_match

void regexMatch(const char* input, const char* expr) {
	string str(input);
	smatch results;
	regex reg(expr);
	if (regex_match(str, results, reg)) {
		for(string x: results)
			cout << x << endl;
	}
}
int main() {
	regexMatch("a  cd", "[a-z][  ]{2}[a-z]*");
	regexMatch("ab123c.cpp", "([^0-9][[:alnum:]]*)\\.(cpp)");
}

  如果匹配成功,第三行的result[0]是整个输入序列。如果像第12行那样使用小括号把表达式分组,result[0]后面的元素就是各分组匹配的输入序列子串。

2. 函数regex_search

3. 函数regex_replace

void regexReplace(const char* input, const char* expr, const char* fmt) {
	string str1(input);
	regex reg(expr);
	string str2(fmt);
	cout << regex_replace(str1, reg, str2) << endl;
}
int main() {
	regexReplace("192-168-1-0", "([[:digit:]]+)-([[:digit:]]+)-([[:digit:]]+)-([[:digit:]]+)", "$1.$2.$3.$4");
	regexReplace("ab123c.cpp", "([[:alnum:]]*)\\.(cpp)", "$1.cxx");
}

  regex_replaceh函数的第三个参数指定格式,实参在第8行:第2个参数使用小括号把表达式分组,第3个参数指定各分组的组合方式。

3.2 字符匹配


字母数字字母或数字字符
[[:alpha:]]等价于([a-z] | [A-Z])[[:digit:]]等价于[0-9][[:alnum:]]等价于([a-z] | [A-Z] | [0-9]).

4. 随机数


4.1 函数rand()


  函数rand()产生[0, RAND_MAX]范围内的随机数。如果不使用srand()函数设置种子,每次运行时产生的多个随机数一般不相等,但程序多次运行的结果是相同的。

cout << RAND_MAX << endl; // 32767 = 2^15-1。
srand((unsigned)time(NULL));
cout << rand() << endl;

  产生一组 [a, b] 之间的随机数,每次运行不相同。注意第 6 行不能写到函数 fun 内!

int fun(int a, int b) {
	return rand() % (b - a + 1) + a;
}

int main() {
	srand((unsigned)time(NULL));
	for (int i = 0; i < 10; i++)
		cout << fun(2, 9) << " ";
	system("pause");
}

4.2 随机数引擎和分布


1. 随机数引擎

default_random_engine e((unsigned)time(NULL));
cout << e.min() << " " << e.max() << endl; // [0, 4294967295=2^32-1]。
cout << e() << endl;

2. 分布类型和引擎

  使用一个分布类型的对象产生指定范围的随机数。

// uniform_int_distribution<int> u(-9, 9); // 产生[-9, 9]之间的随机数。
uniform_int_distribution<unsigned> u(0, 9);
default_random_engine e((unsigned)time(NULL));
cout << u(e) << endl;

3. 引擎生成一个数值序列

  和rand()函数一样,如果不设置种子,使用随机数引擎生成的随机数多次运行结果是相同的。上面的程序设置随机数引擎的种子为(unsigned)time(NULL)。

4.3 随机数例子


  下面我们就使用 C++ 按高斯分布产生随机数。

#include <iostream>
#include <random>

int main(void) {
#if true
    // 每次生成的随机数不同。
    std::random_device rd;
    std::mt19937 gen(rd());
#else
    // 每次生成的随机数相同。
    default_random_engine gen;
#endif
    // 设定均值为 0,标准差为 1。
    std::normal_distribution<double> normal(0.0, 1.0);

    for (int i = 0; i < 10; i++) {
        std::cout << normal(gen) << " ";
    }
    std::cout << std::endl;
    return 0;
}

4.3 其他随机数分布


5. IO 库再探


6. 时间戳


  时间戳可以用于设置随机数种子、文件命名、计时等。
  纪元时间是1970年1月1日0点整。但中国在东8区,纪元时间是1970年1月1日8点整,比如上午9点获取的自纪元至今的小时数是x,则 x = 24 n + 1 x = 24n + 1 x=24n+1

1. C库函数time

time_t t1;
time_t t2 = time(&t1);

  返回自纪元至今经过的秒数。如果参数不为空(0或NULL),返回值也存储在参数中。类型time_t是有符号的long long类型。

2. C++库chrono

#include<chrono>
using namespace std;
using namespace std::chrono;
int main() {
	// 纳秒(精确到100纳秒)
	time_point<system_clock, nanoseconds> clock = time_point_cast<nanoseconds>(system_clock::now());
	time_t time = clock.time_since_epoch().count();
	cout << time << endl;
}

  上面输出自纪元至今经过的百纳秒数。使用microseconds、milliseconds、seconds、minutes、hours输出微秒、毫秒、秒、分钟、小时。其中使用seconds的输出和使用C库函数time(NULL)的输出是一样的。

3. 获取当前时间

#include <chrono>
#include <ctime>
#include <iostream>
#include <sstream>
using namespace std;

void f1() {
    time_t rawtime;
    struct tm info;
    char buffer[80];
    time(&rawtime);
    localtime_s(&info, &rawtime);
    strftime(buffer, 80, "%Y%m%d_%H%M%S", &info);
    cout << "f1: " << buffer << endl;
}

void f2() {
    std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
    std::time_t time_now = std::chrono::system_clock::to_time_t(tp);
    char buf[250];
    // 时间。
    ctime_s(buf, sizeof(buf), &time_now);
    cout << "f2_1: " << buf;
    // 时间戳。
    memset(buf, 0, sizeof(buf));
    tm local_time;
    localtime_s(&local_time, &time_now);
    strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", &local_time);
    cout << "f2_2: " << buf << endl;
}

void f3() {
    std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>
        clock = std::chrono::time_point_cast<std::chrono::nanoseconds>(
            std::chrono::system_clock::now());
    time_t time = clock.time_since_epoch().count();
    cout << "f3: " << time << endl;
}

std::string GetCurrentTimeStamp(int time_stamp_type = 0) {
    std::chrono::system_clock::time_point now =
        std::chrono::system_clock::now();
    std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
    // std::tm *now_tm = std::localtime(&now_time_t);

    tm local_time;
    localtime_s(&local_time, &now_time_t);

    char buffer[128];
    strftime(buffer, sizeof(buffer), "%F %T", &local_time);
    std::ostringstream ss;
    ss.fill('0');
    std::chrono::milliseconds ms;
    std::chrono::microseconds cs;
    std::chrono::nanoseconds ns;
    switch (time_stamp_type) {
    case 0:
        ss << buffer;
        break;
    case 1:
        ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                 now.time_since_epoch()) %
             1000;
        ss << buffer << ":" << ms.count();
        break;
    case 2:
        ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                 now.time_since_epoch()) %
             1000;
        cs = std::chrono::duration_cast<std::chrono::microseconds>(
                 now.time_since_epoch()) %
             1000000;
        ss << buffer << ":" << ms.count() << ":" << cs.count() % 1000;
        break;
    case 3:
        ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                 now.time_since_epoch()) %
             1000;
        cs = std::chrono::duration_cast<std::chrono::microseconds>(
                 now.time_since_epoch()) %
             1000000;
        ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
                 now.time_since_epoch()) %
             1000000000;
        ss << buffer << ":" << ms.count() << ":" << cs.count() % 1000 << ":"
           << ns.count() % 1000;
        break;
    default:
        ss << buffer;
        break;
    }
    return ss.str();
}

void f4() {
    std::cout << GetCurrentTimeStamp(0) << std::endl;
    std::cout << GetCurrentTimeStamp(1) << std::endl;
    std::cout << GetCurrentTimeStamp(2) << std::endl;
    std::cout << GetCurrentTimeStamp(3) << std::endl;
}

int main() {
    f1();
    f2();
    f3();
    f4();
    return 0;
}

7. 参考文献


  1. C++高斯分布随机数生成,优快云,2020。
  2. C++ 时间,脚本之家,2023。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值