C++篇:007

C++篇:007.C++20常用新特性

一、模块

模块是一个用于在翻译单元间分享声明和定义的语言特性。它们可以在某些地方替代使用头文件。

其主要优点如下:

  1. 没有头文件
  2. 声明实现仍然可分离,但非必要。
  3. 可以显式指定导出哪些类或函数。
  4. 不需要头文件重复引入宏(include guards)。
  5. 模块之间名称可以相同,并且不会冲突。
  6. 模块只处理一次,编译更快(头文件每次引入都需要处理,需要通过pragma once约束)。
  7. 预处理宏只在模块内有效。
  8. 模块的引入与引入顺序无关.

如何创建模块

源文件 -> 添加 -> 新建项 -> Module

创建***.ixx文件

//创建模块
//mymodule.ixx	模块名和文件名没有强制要求,一般会相同
export module helloworld; //模块声明
import <iostream>; //导入声明 **注意;号**

export void hello() {
	std::cout << "Hello world!\n";
}


//导入模块
//main.cpp
import helloworld; //导入声明

int main() {
    hello();
}


//模块分区(有时一个模块太大了,就需要分区编写)
//mymodule_partA.ixx
export module Module1:module_partA;//声明现在是Module1模块的子分区:module_partA
//在子模块定义的函数、类等,建议在主模块中声明!!!!!!!!!!!!
//关于export的注意:静态变量、函数以及定义在匿名命名空间中的类、变量和函数,都是具有内部连接的C++实体,不可以导出,下面是一些****************************************************错误案例********************************************************
//mymodule.ixx
export module mymo1;

export static void func1() {}
export static int num = 100;

namespace {
    export class ABC{};
}

二、协程

在编程中,协程(Coroutine) 是一种特殊的函数,可以在执行过程中暂停(挂起)恢复,允许程序在多个任务间灵活切换,而无需依赖操作系统级别的线程调度。与线程相比,协程更轻量(几乎无系统调用开销),且由程序自身控制调度,适合处理高并发 I/O 密集型任务(如网络请求、文件读写等)。

C++提供了三个方法挂起协程:co_await,co_yield,co_return,如果一个函数中存在这三个关键字之一,那么它就是一个协程。

//保存当前协程的执行状态并挂起,返回some_value给调用者
co_yield some_value
//如果some_awaitable没有ready,就保存当前协程的执行状态并挂起
co_await some_awaitable
//彻底结束当前协程,返回some_value给协程调用者
co_return some_value

三、三项比较运算符 <=>

(a <=> b) < 0 //如果a < b则为true
(a <=> b) > 0 //如果a > b则为true
(a <=> b) == 0 //如果a与b相等或等价则为true
    
    
//一般情况:自动生成所有的比较运算符,如果对象是个结构体逐个比较,可以用下面代码代替所有的比较运算符
//高级情况:指定返回类型
auto X::operator<=>(const Y&) = default;

四、范围ranges

void func1(vector<string>& s) {
	sort(s);	//而不是sort(vs.begin(), vs.end());
}

下面是一个示例

#include <vector>
#include <ranges>
#include <iostream>
using namespace std;

int main() {
    auto ints = views::iota(0, 10);//生成0-9
    auto even = [](int i) {return 0 == i % 2;};
    auto square = [](int i) {return i * i;};
    
    for (int i:ints | views::filter(even) | views::transform(square))//filter是筛选器,transform是对筛出来的数进行处理
        cout << i << ' ';
    
    return 0;
}

五、日期和时区

基于chrono标准库的时间支持,和旧的时间工具一起放在

#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;

int main() {
    //创建年
    auto y1 = year(2023);//也可以year{2023}
    cout << y1 << endl;
    auto y2 = 2022y;
    cout << y2 << endl;
    
    //创建月
    auto m1 = month(12);
    cout << m1 << endl;
    auto m2 = July;
    cout << m2 << endl;
    
    //创建日
    auto d1 = day{5};
    auto d2 = 2d;
    cout << d1 << '\n' << d2 << endl;
    
    
    year_month_day date1 {2022y, July, 12d};
    cout << date1 << endl;
    
    auto date2 = 2022y / July / 12d;
    cout << date2 << endl;
    
    year_month_day date3 {Monday[3] / July / 2022};//Monday[3]指第三个周一
    cout << date3 << endl;
    
    return 0;
}

六、格式化

格式化库提供了一种类printf的方式去组装字符串和格式化输出值,这样可以不使用 << 分隔输出值的方式。同时这种方法类型安全、快捷,并能和iostream协同工作。

类型中带有<<运算符的可以在一个格式化的字符串中输出

#include <format>

string s1 = "C++";
//下面的语句中,'{}'代表占位符

//按顺序对应
cout << format("The string '{}' has {} characters", s1, s1.size()) << endl;

//按下标对应
cout << format("The string '{0}' has {1} characters", s1, s1.size()) << endl;
cout << format("The string '{1}' has {0} characters", s1, s1.size()) << endl;

七、跨度

越界访问,有时也称为缓冲区溢出。span类模版就这样被放到C++核心指南的支持库中。

void func(span <int> a) {//span包含一个指针和一条大小信息
	for (int& x : a) {
		x = 7;
	}
}

八、并发

std::promise和std::future是一对,通过它们可以进行更加灵活的任务控制

promise通过函数set_value()传入一个值、异常或者通知,并异步地获取结果

future从promise获取值,询问值是否可用,等待通知,创建shared_future

#include <iostream>
#include <format>
#include <future>
using namesapce std;


void product(promise<int>&& intPromise, int v1, int v2) {
	intPromise.set_value(v1 * v2);
}

void getAnswertest(promise<int> intPromise) {
	this_thread::sleep_for(2s);
	intPromise.set_value(999);
}

void test01() {
	int num1 = 200, num2 = 300;
	promise<int> productPromise;
	
	future<int> productResult = productPromise.get_future();
	jthread productThread(product, move(productPromise), num1, num2);
	
	cout << format("product is {}\n", productResult) << endl;

	return 0;
}

void test02() {
    promise<int> answerPromise;
    auto fut = answerPromise.get_future();
    jthread productThread(getAnswertest, answerPromise);
    future_status status{};
    do {
        status = fut.wait_for(0.5s);
        cout << "结果未准备好!" << endl;
    } while (status != future_status::ready);
    cout << format("answer is {}\n", fut.get()) << endl;
}

九、numbers和concept

numbers

#include <numbers>

void test01() {
	cout << "numbers::e = " << numbers::e << " " << numbers::e_v<double> << endl;
	cout << "numbers::log10e = " << numbers::log10e << " " << numbers::1og10e_v<double> << endl;
}

concept

#include <iostream>
using namespace std;

template<class T>
class ClassTest1 {
public:
	template<typename ToString = T>
	typename enable_if_t<is_convertible<ToString, string>::value, string>
		to_string() const {
			return "ClassTest1<>";
		}
}

//concept改写
template<typename T>
concept CastableToString = requires(T a) {
	{a} -> string;
}

template<typename T>
class ClassTest2 {
public:
	string to_string() const requires CastableToString<T> {
		return "ClassTest2<>";
	}
}
//concept改写完

void test() {
	ClassTest1<size_t> ct1;
	cout << ct1.to_string() << endl;	//编译无法通过
	
	ClassTest1<string> ct2;
	cout << ct2.to_string() << endl;	//编译可以通过
}

void test_concept() {
	ClassTest2<string> ct1;
	cout << ct1.to_string() << endl;
}
posted on 2025-10-15 22:28  Khalilll  阅读(10)  评论(0)    收藏  举报