C++20 新增特性jimmysue.me
constexpr string & vector
consteval 函数
constinit
// cppcon.cpp
export module cppcon;
namespace CppCon {
auto GetWelcomeHelper() { return "Welcome to CppCon 2019!"; }
export auto GetWelcome() { return GetWelcomeHelper();}
}
// main.cpp
import cppcon;
int main(){
std::cout << CppCon::GetWelcome();
}
iostream
转换为模块Ranges 是什么 ?
Range
代表一串元素, 或者一串元素中的一段好处:
vector data{11, 22, 33};
sort(begin(data), end(data));
sort(data); // 使用 Ranges
相关功能
|
串联vector data {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = data |
views::remove_if([](int i) { return i % 2 == 1;}) |
views::transform([](int i) { return to_string(i);});
// result = {"2", "4", "6", "8", "10" };
// 注意 以上操作被延迟, 当你遍历result的时候才触发
vector data{4, 3, 4, 1, 8, 0, 8};
vector result = data | actions::sort | actions::unique;
data
进行更改, 然后返回
int total = accumulate (
view::ints(1) |
view::transform([](int i) {return i * i;}) |
view::take(10),
0);
view::ints(1)
产生一个无限的整型数列accumulate
累加遍历的时候发生co_wait
: 挂起协程, 等待其它计算完成co_return
: 从协程返回 (协程 return
禁止使用)co_yield
: 同 python yield, 弹出一个值, 挂起协程, 下一次调用继续协程的运行for co_await
循环体for co_await (for-range-declaration: expression) statement
用处
experimental::generator GetSequenceGenerator(
int startValue,
size_t numberOfValues) {
for (int i = 0 startValue; i < startValue + numberOfValues; ++i){
time_t t = system_clock::to_time_t(system_clock::now());
cout << std:: ctime(&t); co_yield i;
}
}
int main() {
auto gen = GetSequenceGenerator(10, 5);
for (const auto& value : gen) {
cout << value << "(Press enter for next value)" << endl;
cin.ignore();
}
}
template concept Incrementable = requires(T x) {x++; ++x;};
template
void Foo(T t);
template requires Incrementable
void Foo(T t);
template
void Foo(T t) requires Incrementable;
void Foo(Incrementable auto t);
size()
方法, 且返回size_t
template concept HasSize = requires (T x){
{x.size()} -> std::convertible_to;
};
template
requires Incrementable && Decrementable
void Foo(T t);
// or
template
concept Incr_Decrementable = Incrementable && Decrementable;
template
void Foo(T t);
this
变量[=]
隐式捕获this
[=, this]
可以在lambda
表达式中使用模板语法
[]template(T x) {/* ... */};
[]template(T* p) {/* ... */};
[]template(T (&a)[N]) {/* ... */};
原因1
auto func = [](auto vec){
using T = typename decltype(vec)::value_type;
}
auto func = [](vector vec){
// ...
}
原因2: 方便获取通用lambda形参类型, 访问静态函数
auto func = [](auto const& x){
using T = std::decay_t;
T copy = x; T::static_function();
using Iterator = typename T::iterator;
}
auto func = [](const T& x){
T copy = x; T::static_function();
using Iterator = typename T::iterator;
}
原因3: 完美转发
auto func = [](auto&& ...args) {
return foo(std::forward(args)...);
}
auto func = [](T&& …args){
return foo(std::forward(args)...);
}
template
auto delay_invoke(F f, Args... args){
return [f, args...]{
return std::invoke(f, args...);
}
}
template
auto delay_invoke(F f, Args... args){
// Pack Expansion: args = std::move(args)...
return [f = std::move(f), args = std::move(args)...](){
return std::invoke(f, args...);
}
}
constexpr
) 的更新constexpr
虚函数
constexpr
的虚函数可以重写非 constexpr
的虚函数constexpr
虚函数可以重写 constexpr
的虚函数constexpr
函数可以:
dynamic_cast()
和 typeid
union
成员的值try/catch
throw
语句constexpr std::vector
constexpr
string & vectorstd::string
和 std::vector
类型现在可以作为 constexpr
constexpr
反射mutex
控制智能指针的访问atomic>
, atomic>
mutex
template
class concurrent_stack {
struct Node {
T t;
shared_ptr next;
};
atomic_shared_ptr head;
// C++11: 去掉 "atomic_" 并且在访问时, 需要用
// 特殊的函数控制线程安全, 例如用std::tomic_load
public:
class reference {
shared_ptr p;
};
auto find(T t) const {
auto p = head.load(); // C++11: atomic_load(&head)
while (p && p->t != t)
p = p->next;
return reference(move(p));
}
auto front() const {
return reference(head);
}
void push_front(T t) {
auto p = make_shared();
p->t = t; p->next = head;
while (!head.compare_exchange_weak(p->next, p)){
} // C++11: atomic_compare_exchange_weak(&head, &p->next, p); }
void pop_front() {
auto p = head.load();
while (p && !head.compare_exchange_weak(p, p->next)) {
} // C++11: atomic_compare_exchange_weak(&head, &p, p->next);
}
};
例子来自 Herb Sutter 的 N4162 论文
stop_source.request_stop()
然后 join()
std::stop_token
condition_variable_any
配合使用std::stop_source
std::stop_callback
stop_token
被要求终止, 将会触发回调函数std::thread 在析构函数中如果线程joinable()
会直接调用std::terminate()
直接导致程序退出
void DoWorkPreCpp20() {
std::thread job([] { /* ... */ });
try {
// ... Do something else ...
} catch (...) {
job.join();
throw; // rethrow
}
job.join();
}
void DoWork() {
std::jthread job([] { /* ... */ });
// ... Do something else ...
} // jthread destructor automatically calls join()
std::jthread job([](std::stop_token token) {
while (!token.stop_requested()) {
//...
}
});
//... job.request_stop();
// auto source = job.get_stop_source()
// auto token = job.get_stop_token()
mutex
std::atomic
等待和通知接口
wait()
notify_one()
notify_all()
struct Data {
int anInt = 0;
std::string aString;
};
Data d{ .aString = "Hello" };
auto X::operator<=>(const Y&) = default;
示例:
class Point {
int x; int y;
public:
friend bool operator==(const Point& a, const Point& b){
return a.x==b.x && a.y==b.y;
}
friend bool operator< (const Point& a, const Point& b){
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
friend bool operator!=(const Point& a, const Point& b) {
return !(a==b);
}
friend bool operator<=(const Point& a, const Point& b) {
return !(b (const Point& a, const Point& b) {
return b=(const Point& a, const Point& b) {
return !(a
class Point {
int x; int y;
public:
auto operator<=>(const Point&) const = default; // 比较操作符自动生成
// ... 其他非比较函数 ...
};
struct Foo {
int value; int result;
};
Foo GetData() {
return Foo();
}
int main() {
switch (auto data = GetData(); data.value) {
case 1:
return data.result;
}
}
struct Foo {
int value; int result;
};
Foo* GetData() {
return new Foo();
}
int main() {
if (auto data = GetData(); data) {
// Use 'data’
}
}
struct Foo {
std::vector values;
};
Foo GetData() {
return Foo();
}
int main() {
for (auto data = GetData();
auto& value : data.values) {
// Use 'data’
}
}
template void DoSomething() {
std::cout << s << std::endl;
}
int main() {
DoSomething<"CppCon">();
}
先验概率指导编译器优化
switch (value) {
case 1: break;
[[likely]] case 2: break;
[[unlikely]] case 3: break;
}
// creating a year
auto y1 = year{ 2019 };
auto y2 = 2019y;
// creating a mouth
auto m1 = month{ 9 };
auto m2 = September;
// creating a day
auto d1 = day{ 18 };
auto d2 = 18d;
year_mouth_day fulldate1{2019y, September, 18d};
auto fulldate2 = 2019y / September / 18d;
year_mouth_day fulldate3{Monday[3]/September/2019}; // Monday[3] 表示第三个星期一
using days = duration, hours::period>>;
using weeks = ...; using mouths = ...;
using years = ...;
weeks w{1}; // 1 周
days d{w}; // 将 1 周 转换成天数
system_clock
, steady_clock
, high_resolution_clock
):
utc_clock
: represents Coordinated Universal Time (UTC), measures time since 00:00:00 UTC, Thursday, 1 January 1970, including leap secondstai_clock
: represents International Atomic Time (TAI), measures time since 00:00:00, 1 January 1958, and was offseted 10 seconds ahead of UTC at that date, it does not include leap secondsgps_clock
: represents Global Positioning System (GPS) time, measures time since 00:00:00, 6 January 1980 UTC, it does not include leap secondsfile_clock
: alias for the clock used for std::filesystem::file_time_type
, epoch is unspecifiedsystem_clock
相关的别名template
using sys_time = std::chrono::time_point;
using sys_seconds = sys_time;
using sys_days = sys_time;
// 用例:
system_clock::time_point t = sys_days{ 2019y / September / 18d }; // date -> time_point
auto yearmonthday = year_month_day{ floor(t) }; // time_point -> date
auto t = sys_days{2019y/September/18d} + 9h + 35min + 10s; // 2019-09-18 09:35:10 UTC
// Convert UTC to Denver
time: zoned_time denver = { "America/Denver", t };
// Construct a local time in Denver:
auto t = zoned_time{
"America/Denver", local_days{Wednesday[3] / September / 2019} + 9h
};
// Get current local time:
auto t = zoned_time{ current_zone(), system_clock::now() };
string_view
)int data[42]; span a {data}; // fixed-size: 42 ints
span b {data}; // dynamic-size: 42 ints
span c {data}; // compilation error
span d{ ptr, len }; // dynamic-size: len ints
通过它可以判断编译器是否支持某个功能, 例如
__has_cpp_attribute(fallthrough)
__cpp_binary_literals
__cpp_char8_t
__cpp_coroutines
__cpp_lib_concepts
__cpp_lib_ranges
__cpp_lib_scoped_lock
包含 C++ 标准库版本, 发布日期, 版权证书, 特性宏等
consteval
函数constexpr
函数可能编译期执行, 也可以在运行期执行, consteval
只能在编译器执行, 如果不满足要求编译不通过
constinit
强制指定以常量方式初始化
const char* GetStringDyn() {
return "dynamic init";
}
constexpr const char* GetString(bool constInit) {
return constInit ?
"constant init" :
GetStringDyn();
}
constinit const char* a = GetString(true); // ✔
constinit const char* b = GetString(false); // ❌
using
引用 enum
类型enum class CardTypeSuit {
Clubs,
Diamonds,
Hearts,
Spades
};
std::string_view GetString(const CardTypeSuit cardTypeSuit) {
switch (cardTypeSuit) {
case CardTypeSuit::Clubs:
return "Clubs";
case CardTypeSuit::Diamonds:
return "Diamonds";
case CardTypeSuit::Hearts:
return "Hearts";
case CardTypeSuit::Spades:
return "Spades";
}
}
std::string_view GetString(const CardTypeSuit cardTypeSuit) {
switch (cardTypeSuit) {
using enum CardTypeSuit; // 这里
case Clubs: return "Clubs";
case Diamonds: return "Diamonds";
case Hearts: return "Hearts";
case Spades: return "Spades";
}
}
std::format
)不展开, 类似Python
的格式化,
std::string s = std::format("Hello CppCon {}!", 2019);
再也不用为 M_PI 发愁啦
用于获取代码位置, 对于日志和错误信息尤其有用
表明返回值不可抛弃, 加入理由的支持
[[nodiscard("Ignoring the return value will result in memory leaks.")]]
void* GetData() { /* ... */ }
加入循环移位, 计数0和1位等功能
midpoint
计算中位数, 可避免溢出lerp
线性插值 lerp( float a, float b, float t )
返回 unsequenced_policy(execution::unseq)
std::string str = "Hello world!";
bool b = str.starts_with("Hello"); // starts_with, ends_with
std::map myMap{ std::pair{1, "one"s}, {2, "two"s}, {3, "three"s} };
bool result = myMap.contains(2); // contains, 再也不用 .find() == .end() 了