其他
曾被“劝退”的 C++ 20 正式发布!
【编者按】近日,C++20 标准正式公布,这不禁让人想起了 2018 年年底 C++ 标准委员会讨论 C++ 20 新特性的光景。
当时“ C++ 20 还未发布,就已凉凉?”的论调可谓火热,其中 C++ 模块化更是引起了国内外开发者的嫌弃:C++ 开发者怒了:这个无用的模块设计最终会害死 C++!
这个未出世就被群嘲“劝退”的 C++20 ,如今终于正式发布,那它带来了哪些新特性呢?一起来看大佬实战探究总结!
近日,ISO C++委员会正式发布了 C++20 标准,命名为 ISO/IEC 14882:2020。
Constraints and concepts (约束和概念)
在模板编程中,可以限制模板参数的类型或具用某种特性,如:可以限制为整型、数值型、bool 型、或必须支持 hash 特性、或某个类的派生类型等。
Concepts
template < template-parameter-list >
concept concept-name = constraint-expression;
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};//声明了一个名为Hashable的concept
struct meow {};
template<Hashable T>
void f(T); // 约束这个T必须满足Hashable concept,否则无法编译通过。
int main() {
f("abc"s); // OK,string是可hash的
f(meow{}); // Error: meow结构体不是可hash的,当然可以让其支持hash。
}
//
template<typename T>
concept C=sizeof(T)>10;
template<C T>
class test{};
template<C T>
void func(T t);
Constraints
合取(conjunction) 析取(disjunction) 原子约束(atomic constraint)
template<Incrementable T>
void f(T) requires Decrementable<T>;
template<Incrementable T>
void f(T) requires Decrementable<T>; // OK:重声明
Requires
requires 子句
template<typename T>
void f(T&&) requires Eq<T>; // 可作为函数声明符的最末元素出现
template<typename T> requires Addable<T> // 或在模板形参列表的右边
T add(T a, T b) { return a + b; }
初等表达式,例如 Swappable、std::is_integral::value、(std::is_object_v && …) 或任何带括号表达式 以运算符 && 连接的初等表达式的序列 以运算符 || 连接的前述表达式的序列
requires 表达式
requires { requirement-seq }
requires ( parameter-list(optional) ) { requirement-seq }
requirement-seq - 要求(requirement)的序列,描述于下(每个要求以分号结尾)。
简单要求(simple requirement) 类型要求(type requirement) 复合要求(compound requirement) 嵌套要求(nested requirement)
template<typename T>
concept Addable = requires (T x) { x + x; }; // requires 表达式
template<typename T> requires Addable<T> // requires 子句,非 requires 表达式
T add(T a, T b) { return a + b; }
template<typename T>
requires requires (T x) { x + x; } // 随即的约束,注意关键字被使用两次
T add(T a, T b) { return a + b; }
主要有三个关键字:
module:用于声明一个模块 export:用于导出模块、函数或类 import:用于导入模块
定义了一个 helloworld 模块,导出了 hello 函数
//helloworld.cpp
export module helloworld; // module declaration
import <iostream>; // import declaration
export void hello() { // export declaration
std::cout << "Hello world!\n";
}
//main.cpp
import helloworld;
int main()
{
hello();
}
co_await
co_await 暂停当前协程的执行,直到等待的操作完成后继续执行。
task<> tcp_echo_server() {
char data[1024];
for (;;) {
std::size_t n = co_await socket.async_read_some(buffer(data)); #与 Python 中的 await 类似
co_await async_write(socket, buffer(data, n));
}
}
co_yield
co_yield 暂停执行并返回一个值,与 return 不同的是 co_yield 虽然返回了值 ,但当前函数没有终止。
generator<int> iota(int n = 0) {
while(true)
co_yield n++; //与 Python 中的 yield 类似
}
co_return
co_return 用于结束当前协程的执行并返回一个值
lazy<int> f() {
co_return 7;
}
不能使用变长实参; 不能使用普通的 return 语句,或占位符返回类型(auto 或 Concept); constexpr 函数、构造函数、析构函数及 main 函数不能是协程。
Ranges(范围)
主要有如下几类:
基于范围的访问器 基于范围的原语 基于范围的 concept 视图 工厂 适配器
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector<int> ints{0,1,2,3,4,5};
auto even = [](int i){ return 0 == i % 2; };
auto square = [](int i) { return i * i; };
for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
std::cout << i << ' ';
}
}
Designated Initializers(指定初始化)
struct A{int a;int b;int c;};
A a{.a=10,.b=100,.c=20};
operator<=>
lhs <=> rhs
(a <=> b) < 0 if lhs < rhs
(a <=> b) > 0 if lhs > rhs
(a <=> b) == 0 if lhs equal rhs
#include <compare>
#include <iostream>
int main() {
double foo = -0.0;
double bar = 0.0;
auto res = foo <=> bar;
if (res < 0)
std::cout << "-0 is less than 0";
else if (res == 0)
std::cout << "-0 and 0 are equal";
else if (res > 0)
std::cout << "-0 is greater than 0";
}
Attributes(特性)
[[nodiscard( string-literal )]]:忽略返回值时警告。 [[likely]] 和[[unlikely]]:指示编译器优化更可能出现的情况或分支。是一种对变量值出现可能性的一种预判。
int f(int i)
{
if (i < 0) [[unlikely]] {
return 0;
}
return 1;
}
constexpr 新增对虚函数的支持。
char8_t 用于存储utf-8的字符串。
constinit
const char * g() { return "dynamic initialization"; }
constexpr const char * f(bool p) { return p ? "constant initializer" : g(); }
constinit const char * c = f(true); // OK
constinit const char * d = f(false); // error
labmda
允许以值的形式显示捕获 this;
支持模板,且支持可变参数;
template <typename... Args>
void foo(Args... args) {
[...xs=args]{
bar(xs...); // xs is an init-capture pack
};
}
std::format
#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello {}!\n", "world");
}
std::span
std::jthread
Calendar 和 time zone
endian 用于判断大小端的枚举
std::make_shared 支持数组
atomic 支持浮点数和 smart ptr
std::basic_syncbuf 和 std::basic_osyncstream
string 增加 starts_with 和 end_with 函数
std::atomic_ref 原子引用
std::to_array 将 xxx 转换为 std::array
inline namespace
特性概览
核心功能特性概览
library features
https://en.cppreference.com/w/cpp/20
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2131r0.html
草案版本:
https://github.com/cplusplus/draft/tree/c++20
☞小米11定档12月28日;马斯克曾考虑把特斯拉卖给苹果却被拒;TiDB 4.0.9发布|极客头条
☞Rust 2020 调查报告出炉,95%的开发者吐槽Rust难学