c++20的新增的小的特性

news/2024/11/15 15:14:59/

c++20的新增的小的特性

c++20新增的特性非常多,其中concept,coroutine,module和range为四大特性,在之前的章节中已有涉及,本文则对其他的一些小改动进行讲解。

  • c++20的新增的小的特性
    • std::format
    • Calendar
    • timezone
    • std::source_location
    • std::span
    • 航天飞机运算符 <=>
    • std::endian判断大小端
    • std::remove_cvref
    • bind_front
    • std::atomic_ref
    • std::map<Key,T,Compare,Allocator>::contains
    • std::barrier
    • std::latch锁存器
    • std::counting_semaphore
    • string::starts_with / ends_with
    • std::size
    • std::is_bounded_array_v和std::is_unbounded_array
    • std::erase_if
    • Mathematical constants
    • std::midpoint
    • std::lerp

std::format

c++20支持新的字符串格式化方式std::format

#include <format>
#include <iostream>using namespace std;int main()
{// Declare variablesint num = 42;std::string name = "John";// Use std::format to format a string with placeholders// for variablesstd::string formatted_str = std::format("My name is {} and my favorite number is {}", name,num);// Print formatted string to consolestd::cout << formatted_str << std::endl;return 0;
}

Calendar

#include <chrono>int main()
{using namespace std::chrono;// Get a local time_point with system_clock::duration precisionauto now = zoned_time{current_zone(), system_clock::now()}.get_local_time();// Get a local time_point with days precisionauto ld = floor<days>(now);// Convert local days-precision time_point to a local {y, m, d} calendaryear_month_day ymd{ld};// Split time since local midnight into {h, m, s, subseconds}hh_mm_ss hms{now - ld};// This part not recommended.  Stay within the chrono type system.int year{ymd.year()};int month = unsigned{ymd.month()};int day = unsigned{ymd.day()};int hour = hms.hours().count();int minute = hms.minutes().count();int second = hms.seconds().count();
}

timezone

时区工具

#include <chrono>
#include <iostream>int main() {const std::chrono::zoned_time cur_time{ std::chrono::current_zone(),std::chrono::system_clock::now() };std::cout << cur_time << '\n';
}

std::source_location

文件位置的工具

#include <iostream>
#include <source_location>
#include <string_view>void log(const std::string_view message,const std::source_location location =std::source_location::current())
{std::clog << "file: "<< location.file_name() << '('<< location.line() << ':'<< location.column() << ") `"<< location.function_name() << "`: "<< message << '\n';
}template<typename T>
void fun(T x)
{log(x);
}int main(int, char*[])
{log("Hello world!");fun("Hello C++20!");
}

std::span

过去如果一个函数想接受无法确定数组长度的数组作为参数,那么一定需要声明两个参数:数组指针和长度:

void set_data(int *arr, int len) {}int main()
{int buf[128]{ 0 };set_data(buf, 128);
}

这种人工输入增加了编码的风险,数组长度的错误输入会引发程序的未定义行为,甚至是成为可被利用的漏洞。C++20标准库为我们提供了一个很好解决方案std::span,通过它可以定义一个基于连续序列对象的视图,包括原生数组,并且保留连续序列对象的大小。例如:

#include <iostream>
#include <span>
void set_data(std::span<int> arr) {std::cout << arr.size();
}int main()
{int buf[128]{ 0 };set_data(buf);
}

航天飞机运算符 <=>

(a <=> b) < 0 if a < b,
(a <=> b) > 0 if a > b,
(a <=> b) == 0 if a and b are equal/equivalent.
#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 is greater than 0";else if (res == 0)std::cout << "-0 and 0 are equal";elsestd::cout << "-0 and 0 are unordered";
}

std::endian判断大小端

#include <bit>
#include <iostream>int main()
{if constexpr (std::endian::native == std::endian::big)std::cout << "big-endian\n";else if constexpr (std::endian::native == std::endian::little)std::cout << "little-endian\n";elsestd::cout << "mixed-endian\n";
}

std::remove_cvref

去除cv和引用

#include <type_traits>int main()
{static_assert(std::is_same_v<std::remove_cvref_t<int>, int>);static_assert(std::is_same_v<std::remove_cvref_t<int&>, int>);static_assert(std::is_same_v<std::remove_cvref_t<int&&>, int>);static_assert(std::is_same_v<std::remove_cvref_t<const int&>, int>);static_assert(std::is_same_v<std::remove_cvref_t<const int[2]>, int[2]>);static_assert(std::is_same_v<std::remove_cvref_t<const int(&)[2]>, int[2]>);static_assert(std::is_same_v<std::remove_cvref_t<int(int)>, int(int)>);
}

bind_front

和std::bind是一个系列的方法,bind_front可以绑定前n个参数而不用敲placeholder。

#include <functional>
#include <iostream>int main()
{auto calc=[](int a, int b, int c) { return a+b-c;};auto aa = std::bind_front(calc, 1,2);std::cout << aa (3)<<"\n";auto bb = std::bind_front(calc, 1,2,3);std::cout << bb ()<<"\n";auto cc=std::bind(calc, 1,std::placeholders::_2,std::placeholders::_1);std::cout<<cc(3,2)<<"\n";   auto dd=std::bind(calc, std::placeholders::_1,std::placeholders::_2,3);std::cout<<dd(1,2); 
}

std::atomic_ref

原子引用

在下面的例子中,最终将打印100

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>int do_count(int value)
{std::atomic<int> counter { value };std::vector<std::thread> threads;for (int i = 0; i < 10; ++i){threads.emplace_back([&counter]() {for (int i = 0; i < 10; ++i){++counter;{using namespace std::chrono_literals;std::this_thread::sleep_for(50ms);}}});}for (auto& t : threads) t.join();return counter;
}int main()
{int result = do_count(0);std::cout << result << '\n'; // prints 100
}

std::atomic并作用于引用不生效, 下面的例子将打印0。

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>void do_count_ref(int& value)
{std::atomic<int> counter{ value };std::vector<std::thread> threads;for (int i = 0; i < 10; ++i){threads.emplace_back([&counter]() {for (int i = 0; i < 10; ++i){++counter;{using namespace std::chrono_literals;std::this_thread::sleep_for(50ms);}}});}for (auto& t : threads) t.join();
}int main()
{int value = 0;do_count_ref(value);std::cout << value << '\n'; // prints 0
}

使用atimic_ref进行修改,可以打印100。

#include <atomic>
#include <thread>
#include <vector>
#include <iostream>void do_count_ref(int& value)
{std::atomic_ref<int> counter{ value };std::vector<std::thread> threads;for (int i = 0; i < 10; ++i){threads.emplace_back([&counter]() {for (int i = 0; i < 10; ++i){++counter;{using namespace std::chrono_literals;std::this_thread::sleep_for(50ms);}}});}for (auto& t : threads) t.join();
}int main()
{int value = 0;do_count_ref(value);std::cout << value << '\n'; // prints 0
}

std::map<Key,T,Compare,Allocator>::contains

map新增contains方法,在此之前使用的是find或者count。

#include <iostream>
#include <map>int main()
{std::map<int,char> example = {{1,'a'},{2,'b'}};for(int x: {2, 5}) {if(example.contains(x)) {std::cout << x << ": Found\n";} else {std::cout << x << ": Not found\n";}}
}

std::barrier

线程屏障

#include <barrier>
#include <iostream>
#include <string>
#include <thread>
#include <vector>int main()
{const auto workers = { "Anil", "Busara", "Carl" };auto on_completion = []() noexcept{// locking not needed herestatic auto phase = "... done\n" "Cleaning up...\n";std::cout << phase;phase = "... done\n";};std::barrier sync_point(std::ssize(workers), on_completion);auto work = [&](std::string name){std::string product = "  " + name + " worked\n";std::cout << product;  // ok, op<< call is atomicsync_point.arrive_and_wait();product = "  " + name + " cleaned\n";std::cout << product;sync_point.arrive_and_wait();};std::cout << "Starting...\n";std::vector<std::jthread> threads;threads.reserve(std::size(workers));for (auto const& worker : workers)threads.emplace_back(work, worker);
}

std::latch锁存器

latch = single-use barrier.


#include <functional>
#include <iostream>
#include <latch>
#include <string>
#include <thread>int main() {struct job {const std::string name;std::string product{"not worked"};std::thread action{};} jobs[] = {{"annika"}, {"buru"}, {"chuck"}};std::latch work_done{std::size(jobs)};std::latch start_clean_up{1};auto work = [&](job& my_job) {my_job.product = my_job.name + " worked";work_done.count_down();start_clean_up.wait();my_job.product = my_job.name + " cleaned";};std::cout << "Work starting... ";for (auto& job : jobs) {job.action = std::thread{work, std::ref(job)};}work_done.wait();std::cout << "done:\n";for (auto const& job : jobs) {std::cout << "  " << job.product << '\n';}std::cout << "Workers cleaning up... ";start_clean_up.count_down();for (auto& job : jobs) {job.action.join();}std::cout << "done:\n";for (auto const& job : jobs) {std::cout << "  " << job.product << '\n';}
}

std::counting_semaphore

计数信号量

#include <chrono>
#include <iostream>
#include <semaphore>
#include <thread>// global binary semaphore instances
// object counts are set to zero
// objects are in non-signaled state
std::binary_semaphoresmphSignalMainToThread{0},smphSignalThreadToMain{0};void ThreadProc()
{// wait for a signal from the main proc// by attempting to decrement the semaphoresmphSignalMainToThread.acquire();// this call blocks until the semaphore's count// is increased from the main procstd::cout << "[thread] Got the signal\n"; // response message// wait for 3 seconds to imitate some work// being done by the threadusing namespace std::literals;std::this_thread::sleep_for(3s);std::cout << "[thread] Send the signal\n"; // message// signal the main proc backsmphSignalThreadToMain.release();
}int main()
{// create some worker threadstd::thread thrWorker(ThreadProc);std::cout << "[main] Send the signal\n"; // message// signal the worker thread to start working// by increasing the semaphore's countsmphSignalMainToThread.release();// wait until the worker thread is done doing the work// by attempting to decrement the semaphore's countsmphSignalThreadToMain.acquire();std::cout << "[main] Got the signal\n"; // response messagethrWorker.join();
}

string::starts_with / ends_with

字符串开头/结尾

#include <iostream>
#include <string>
#include <string_view>template<typename PrefixType>
void test_prefix_print(const std::string& str, PrefixType prefix)
{std::cout << '\'' << str << "' starts with '" << prefix << "': "<< str.starts_with(prefix) << '\n';
}int main()
{std::boolalpha(std::cout);auto helloWorld = std::string("hello world");test_prefix_print(helloWorld, std::string_view("hello"));test_prefix_print(helloWorld, std::string_view("goodbye"));test_prefix_print(helloWorld, 'h');test_prefix_print(helloWorld, 'x');
}

std::size

size的common方法

#include <iostream>
#include <vector>int main()
{std::vector<int> v{3, 1, 4};std::cout << std::size(v) << '\n';int a[]{-5, 10, 15};std::cout << std::size(a) << '\n';// since C++20 the signed size (ssize) is availableauto i = std::ssize(v);for (--i; i != -1; --i)std::cout << v[i] << (i ? ' ' : '\n');std::cout << "i = " << i << '\n';
}

std::is_bounded_array_v和std::is_unbounded_array

#include <iostream>
#include <type_traits>#define OUT(...) std::cout << #__VA_ARGS__ << " : " << __VA_ARGS__ << '\n'class A {};int main()
{std::cout << std::boolalpha;OUT(std::is_bounded_array_v<A>);OUT(std::is_bounded_array_v<A[]>);OUT(std::is_bounded_array_v<A[3]>);OUT(std::is_bounded_array_v<float>);OUT(std::is_bounded_array_v<int>);OUT(std::is_bounded_array_v<int[]>);OUT(std::is_bounded_array_v<int[3]>);
}
#include <iostream>
#include <type_traits>#define OUT(...) std::cout << #__VA_ARGS__ << " : " << __VA_ARGS__ << '\n'class A {};int main()
{std::cout << std::boolalpha;OUT( std::is_unbounded_array_v<A> );OUT( std::is_unbounded_array_v<A[]> );OUT( std::is_unbounded_array_v<A[3]> );OUT( std::is_unbounded_array_v<float> );OUT( std::is_unbounded_array_v<int> );OUT( std::is_unbounded_array_v<int[]> );OUT( std::is_unbounded_array_v<int[3]> );
}

std::erase_if

按照条件erase数据

#include <iostream>
#include <numeric>
#include <string_view>
#include <vector>void print_container(std::string_view comment, const std::vector<char>& c)
{std::cout << comment << "{ ";for (auto x : c)std::cout << x << ' ';std::cout << "}\n";
}int main()
{std::vector<char> cnt(10);std::iota(cnt.begin(), cnt.end(), '0');print_container("Initially, cnt = ", cnt);std::erase(cnt, '3');print_container("After erase '3', cnt = ", cnt);auto erased = std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });print_container("After erase all even numbers, cnt = ", cnt);std::cout << "Erased even numbers: " << erased << '\n';
}

对比之前的remove_if和erase

#include <iostream>
#include <vector>
#include <algorithm>bool isEven(int n) // 是否是偶数
{return n % 2 == 0;
}int main()
{std::vector<int> vecTest;for (int i = 0; i < 10; ++i)vecTest.push_back(i);for (int i = 0; i < vecTest.size(); ++i)std::cout << vecTest[i] << " ";std::cout << std::endl;// 移动元素std::vector<int>::iterator itor = std::remove_if(vecTest.begin(), vecTest.end(), isEven);// 查看移动后的变化for (int i = 0; i < vecTest.size(); ++i)std::cout << vecTest[i] << " ";std::cout << std::endl;// 删除元素vecTest.erase(itor, vecTest.end());for (int i = 0; i < vecTest.size(); ++i)std::cout << vecTest[i] << " ";return 0;
}

Mathematical constants

c++20新增了一些数学常量

#include <numbers>
#include <iostream>int main() {std::cout << std::numbers::log2e_v<double> << std::endl;
}

std::midpoint

#include <cstdint>
#include <iostream>
#include <limits>
#include <numeric>int main()
{std::uint32_t a = std::numeric_limits<std::uint32_t>::max();std::uint32_t b = std::numeric_limits<std::uint32_t>::max() - 2;std::cout << "a: " << a << '\n'<< "b: " << b << '\n'<< "Incorrect (overflow and wrapping): " << (a + b) / 2 << '\n'<< "Correct: " << std::midpoint(a, b) << "\n\n";auto on_pointers = [](int i, int j){char const* text = "0123456789";char const* p = text + i;char const* q = text + j;std::cout << "std::midpoint('" << *p << "', '" << *q << "'): '"<< *std::midpoint(p, q) << "'\n";};on_pointers(2, 4);on_pointers(2, 5);on_pointers(5, 2);on_pointers(2, 6);
}

std::lerp

线性计算

a+t(b-a)

#include <cassert>
#include <cmath>
#include <iostream>float naive_lerp(float a, float b, float t)
{return a + t * (b - a);
}int main()
{std::cout << std::boolalpha;const float a = 1e8f, b = 1.0f;const float midpoint = std::lerp(a, b, 0.5f);std::cout << "a = " << a << ", " << "b = " << b << '\n'<< "midpoint = " << midpoint << '\n';std::cout << "std::lerp is exact: "<< (a == std::lerp(a, b, 0.0f)) << ' '<< (b == std::lerp(a, b, 1.0f)) << '\n';std::cout << "naive_lerp is exact: "<< (a == naive_lerp(a, b, 0.0f)) << ' '<< (b == naive_lerp(a, b, 1.0f)) << '\n';std::cout << "std::lerp(a, b, 1.0f) = " << std::lerp(a, b, 1.0f) << '\n'<< "naive_lerp(a, b, 1.0f) = " << naive_lerp(a, b, 1.0f) << '\n';assert(not std::isnan(std::lerp(a, b, INFINITY))); // lerp here can be -infstd::cout << "Extrapolation demo, given std::lerp(5, 10, t):\n";for (auto t{-2.0}; t <= 2.0; t += 0.5)std::cout << std::lerp(5.0, 10.0, t) << ' ';std::cout << '\n';
}

http://www.ppmy.cn/news/360724.html

相关文章

python代码热更原理及实现

一、简介&#xff1a; 热更&#xff0c;指程序具有在运行过程中修改代码&#xff0c;不重启&#xff0c;而直接生效的能力。 热更对代码的微调&#xff0c;debug非常友好&#xff0c;不再需要重新启动程序&#xff0c;能直接在已有的上下文环境中直接测试。 二、接入流程&am…

宁愿给新员工开高薪,也不愿意给老员工涨薪,那些大厂老板都是怎么想的?

事情是这样的&#xff0c;作为公司2年工龄的测试老员工&#xff0c;技术过关&#xff0c;独当一面&#xff0c;领导对我也很放心。 原本只想涨个30%的薪水&#xff0c;就留下来勤勤恳恳和公司共进退&#xff0c;但HR死活不肯&#xff0c;各种规章制度卡得死死的&#xff0c;顶…

老板该关心什么?

今天到我们的合作伙伴处看看&#xff0c;听说他们公司实施的ERP已上线&#xff0c;也看看使用效果&#xff0c;随即问一问员工&#xff0c;又问一问老板&#xff0c;沟通一会&#xff0c;突然有个想法&#xff0c;象他们这样高速成长的公司岂止他们一家。从树木看森林&#xff…

中国新厨房,老板电器的未来有多大?

中国企业&#xff0c;一度很躁动。在“不要把鸡蛋放在同一个篮子里”这句话的驱使下&#xff0c;做地产的布局汽车、快消&#xff0c;做航空的进军地产、健康&#xff0c;做视频的踏足硬件、消费。而品类扩张成为家电行业的通用技法。 上世纪80年代&#xff0c;老板电器开始进…

一个小公司老板的日常管理

1. 小公司如何留住骨干&#xff1a; 2.关于授权 3.有的钱不能省 5.关于招聘 6.老板尽量唱红脸 7.公司里的亲戚 8.当老板和开车 9.按时发工资 10.学会说“不” 11.不要在公司内部奢望交朋友 12.避免当场做决定 13.政策的制定 14.矬子里拔将军 15.有些事情越透明越好 16.发劳保用…

卓老板之今日金句1

从未有过一个真正有用并且深邃的理论是真的依靠纯粹思辨而发现的。 ⏤⏤ 阿尔伯特爱因斯坦 文章&#xff1a; 《极限&#xff1a;为什么电价夜间减半&#xff1f;》&#xff0c;请在微信客户端打开链接。

你就这样被坏老板决定了?

有位朋友在分答上问过我一个问题&#xff1a; 跟同事抱怨工作的事情是要坚决避免的低情商行为么&#xff1f; 这让我想起我们充满抱怨的工作来啦&#xff1a; 经理根本就不懂技术&#xff0c;凭什么领导我&#xff1f;就因为我不加班&#xff0c;就让我绩效是D&#xff0c;太不…

转:你“恨”你的老板吗

个人理解&#xff1a;恨老板&#xff1f;老板离你还有八丈远&#xff0c;不如说是恨顶头上司、领导&#xff1b;画无数个圈圈诅咒他&#xff0c;祖宗十八代问候个遍。为什么&#xff1f;矛盾、难以琢磨的上下级关系&#xff0c;看对超、合拍不易。 要走要留痛快点&#xff0c;只…