虫虫首页|资源下载|资源专辑|精品软件
登录|注册

您现在的位置是:首页 > 技术阅读 >  C++20最重要的三个新特性

C++20最重要的三个新特性

时间:2024-02-15

C++之父都说过,C++20是C++语言的一次重大变革,引入了大量的新特性。

这其中个人认为最重要新特性是这三个:

  • Modules

  • Coroutines

  • Concepts

Modules

直接看代码:

// helloworld.ixxexport module helloworld;  // module declarationimport <iostream>;         // import declarationexport void hello() {      // export declaration    std::cout << "Hello world!\n";}


// main.cpp\n import helloworld;  // import declarationint main() {    hello();}

每个C++开发者应该都知道include方式是将header中的代码拷贝一份到源文件中,在大的工程项目中还有很多冗余的include,种种原因,导致编译速度相当的慢,而modules却大大改善了这种问题。

modules使用方式和include差不多,但modules使用比include头文件速度更快,C++全球开发者大会中,C++之父贴出来过测试数据,modules效率比include高了25倍。

以后modules肯定会是主流使用方式。

Coroutines

协程是一种比线程和进程更高效的多任务处理模型。

在C++20中,终于把协程引了进来,协程具体还分为有栈协程和无栈协程,两者对比,无栈协程是更高效的协程。

而C++20支持的就是无栈协程,为此提供了三个关键字:

  • co_await:暂停执行,直到恢复

  • co_yield:暂停执行,返回一个值

  • co_return:完成执行,返回一个值


这是一段cppreference上,协程相关的示例代码:

#include <coroutine>#include <iostream>#include <stdexcept>#include <thread>auto switch_to_new_thread(std::jthread& out) {  struct awaitable {    std::jthread* p_out;    bool await_ready() { return false; }    void await_suspend(std::coroutine_handle<> h) {      std::jthread& out = *p_out;      if (out.joinable())        throw std::runtime_error("Output jthread parameter not empty");      out = std::jthread([h] { h.resume(); });      // Potential undefined behavior: accessing potentially destroyed *this      // std::cout << "New thread ID: " << p_out->get_id() << '\n';      std::cout << "New thread ID: " << out.get_id() << '\n'; // this is OK    }    void await_resume() {}  };  return awaitable{&out};}
struct task{ struct promise_type { task get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} };};
task resuming_on_new_thread(std::jthread& out) { std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n'; co_await switch_to_new_thread(out); // awaiter destroyed here std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n';}
int main() { std::jthread out; resuming_on_new_thread(out);}

目前C++20只是从语法层面对协程做了支持,还没有相关的协程库,要想使用协程,还需要引入协程库,但不可否认,C++20已经支持了协程,以后在这方面肯定会越来越完善。

前一段时间参加的C++全球开发者大会,C++之父也说过会全力在C++23标准中引入对协程库的支持。

Concepts

Concepts在模板编程中起到重大的作用, 类模板、函数模板和非模板函数(通常是类模板的成员)可以与一个约束相关联,这个约束指定了对模板实参的要求,这些实参可用于选择最合适的函数重载和模板特化。

很多人应该都知道SFINAE,在C++20前多数都在使用std::enable_if,这相当的麻烦,代码可读性也不高,编译器报错信息也不是很友好,而有了Concepts就方便的多, 每个Concepts都是一个谓词,在编译时计算,并成为模板接口的一部分,在那里它被用作约束:

#include <string>#include <cstddef>#include <concepts>template<typename T>concept Hashable = requires(T a) {    { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;};struct meow {};// Constrained C++20 function template:template<Hashable T>void f(T) {}
int main() { using std::operator""s; f("abc"s); // OK, std::string satisfies Hashable //f(meow{}); // Error: meow does not satisfy Hashable}

其实C++20还有一些特性我比较喜欢,比如std::jthread,真真切切的解决了std::thread存在的旧有问题。

还有fmt,因为cout方式输出复杂的格式很麻烦:比如我想输出a + b = c:

std::cout << a << " + " << b << " = " << c << std::endl;

是不是很麻烦,那可以使用printf?

printf("%d + %d = %d \n", a, b, c);

但printf需要开发者填入变量格式,如果填写有误,有可能打印错误,也有可能crash

  • 某个long long 型,使用%d打印会怎么样?

  • 某个int32_t型,使用%lld打印会怎么样?

  • 某个const char* 型,使用%d打印会怎么样?

  • 某个float型,使用%d打印会怎么样?


所以使用printf会给开发者带来负担,一定要在打印前确认变量的类型,并且一定要保证配置的输出格式正确,我想大多数人可能都会在print某个变量前搜索过打印某个类型需要使用哪种格式吧

那用啥呢?cout配合format

std::cout << std::format("{} + {} = {} \n", a, b, c);

C++20其实还有很多有意思的新特性,而这些特性在这本书中都有详细的介绍,大家感兴趣可以看看。