
- 检查是否存在由属性标记命名的属性,例如deprecated等
#include
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(deprecated)
#define DEPRECATED(msg) [[deprecated(msg)]]
#endif
#endif
#ifndef DEPRECATED
#define DEPRECATED
#endif
DEPRECATED("the func has been deprecated")
void func()
{
std::cout << "test";
}
int main()
{
func();
getchar();
return 0;
}
operator<=>
- 用于两个相同的值进行大小相等判断
#include
#include
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 // (res == 0)
std::cout << "-0 and 0 are equal";
}
//输出结果:-0 and 0 are equal
聚合初始化
- 可通过结构体变量名指定初始化
struct test
{
int a;
int b;
};
int main()
{
test t{ .b = 10, .a = 20 };//error
test t{ .a = 10, .b = 20 };
return 0;
}
char8_t
- 新增的宽字符串
- 适用于在不是位字段的非静态数据成员的声明中声明的名称,编译器可以优化它以不占用空间
#include
struct Empty {}; // empty class
struct X {
int i;
Empty e;
};
struct Y {
int i;
[[no_unique_address]] Empty e;
};
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
struct W {
char c[2];
[[no_unique_address]] Empty e1, e2;
};
[[likely]] & [[unlikely]]
- 允许编译器针对以下情况进行优化:包含该语句的执行路径比不包含此类语句的任何替代执行路径更有可能
if(x)[[likely]]
{
std::cout << 1;
}
else[[unlikely]]
{
std::cout << 2;
}
consteval & constinit
- consteval- 指定一个函数是一个立即函数,即每次调用该函数都必须产生一个编译时常量s
constexpr unsigned factorial(unsigned n) {
return n < 2 ? 1 : n * factorial(n - 1);
}
consteval unsigned combination(unsigned m, unsigned n) {
return factorial(n) / factorial(m) / factorial(n - m);
}
static_assert(factorial(6) == 720);
static_assert(combination(4,8) == 70);
int main(int argc, const char*[]) {
constexpr unsigned x{factorial(4)};
std::cout << x << '\n';
[[maybe_unused]]
unsigned y = factorial(argc); // OK
// unsigned z = combination(argc, 7); // error: 'argc' 不是一个常量表达式
}
- 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
Coroutines
- 协程是一个可以暂停执行以便稍后恢复的函数。协程是无堆栈的:它们通过返回给调用者来暂停执行,并且恢复执行所需的数据与堆栈分开存储。这允许异步执行的顺序代码。目前C++20并没有封装好的类库,使用还是比较繁琐,可以等C++23看看
#include
#include
//编译环境 vs2017
struct generator
{
struct promise_type;
using handle = std::experimental::coroutine_handle<promise_type>;
struct promise_type
{
static auto get_return_object_on_allocation_failure() { return generator(nullptr); }
auto get_return_object() { return generator{ handle::from_promise(*this) }; }
auto initial_suspend() { return std::experimental::suspend_always{}; }
auto final_suspend() { return std::experimental::suspend_always{}; }
void unhandled_exception() { std::terminate(); }
void return_void() {}
//auto return_value(int value) { return value; }
};
bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
int current_value() { return coro.promise().current_value; }
generator(generator const &) = delete;
generator(generator &&rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
~generator() { if (coro) coro.destroy(); }
private:
generator(handle h) : coro(h) {}
handle coro;
};
generator f()
{
std::cout << "hello";
co_await std::experimental::suspend_always();
std::cout << "world";
}
int main()
{
auto ret = f();
while (ret.move_next())
{
std::cout << " ";
}// hello world
getchar();
return 0;
}
Modules
- 模块是一种跨翻译单元共享声明和定义的语言功能。它们是一些头文件用例的替代方案
// A.cpp
export module A;
export import :B;
import :C;
export char const* World() {
return WorldImpl();
}
// A-B.cpp
export module A:B;
export char const* Hello() { return "Hello"; }
// A-C.cpp
module A:C;
char const* WorldImpl() { return "World"; }
// main.cpp
import A;
import ;
int main()
{
std::cout << Hello() << ' ' << World() << '\n';
}
Concepts
- 类模板、函数模板和非模板函数(通常是类模板的成员)可能与一个约束相关联,该约束指定了对模板参数的要求,可用于选择最合适的函数重载和模板特化,更多详情查看
template<typename T>
concept Addable = requires (T obj) {{obj + obj}->std::same_as<T>;};//约束a+b的类型必须和T类型一致
T add(T a, T b)
{
return a + b;
}
新增标准库函数
std::format
- 替代sprintf
#include
#include
int main() {
std::string message = std::format("The answer is {}.", 42);//The answer is 42.
std::string buffer;
std::format_to(std::back_inserter(buffer), "Hello, C++{}!\n", "20");//向后插入,Hello, C++20!
auto buff = "{0}:{1}:{2}";
auto h = 17;
auto m = 46;
auto s = 55;
auto size = std::format_size(buff, h, m, s);
std::string ti;
ti.resize(size);
std::format_to_n(const_cast<char*>(ti.c_str()), ti.size(), buff, h, m, s);
ti.push_back(')';//17:46:55}
日历时间库
std::chrono
- #
include#
includelong
fibonacci (unsigned) nif
{
( <n 2 )return ; nreturn
fibonacci (-n1)+ fibonacci (-n2);}
int
main ()auto
{
= start :: std::chrono::steady_clocknow();::
std<<cout "f(42) = " << fibonacci (42)<< '\n' ;auto
= end :: std::chrono::steady_clocknow();::
std::chrono<durationdouble=> elapsed_seconds - end;start::
std<<cout "elapsed time: " << . elapsed_secondscount()<< "s\n" ;//elapsed time: 1.88232s
}
代码信息,可用于日志
std::source_location
- #
include#
include#
includevoid
log (const:: std,string_view messageconst
:: std=source_location location ::
std::source_locationcurrent())::
{
std<<cout "file: " <<
. locationfile_name()<< "(" <<
. locationline()<< ":" <<
. locationcolumn()<< ") `" <<
. locationfunction_name()<< "`: " <<
<< message '\n' ;}
template
< typenameT void> fun ()T xlog
{
()x;}
int
main (int,char *[])log
{
("Hello world!");//file: main.cpp(24:8) `int main(int, char**)`: Hello world!fun
("Hello C++20!");//file: main.cpp(19:8) `void fun(T) [with T = const char*]`: Hello C++20!}
数组视图,类似于std::string_view
std::span
- #
include#
include template
<classT ,:: std[size_t N> []nodiscard]constexpr
auto slide (::std<span,T,N> s:: std,size_t offset:: std)size_t widthreturn
{
. ssubspan(,offset+ offset <= width . ssize()? : width 0U );}
void
print (constauto &) seqfor
{
( constauto &: elem ) seq:: std<<cout << elem ' ' ;::
std<<cout '\n' ;}
int
main ()constexpr
{
int [ a]0 { ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 } ;for
( ::std}size_t offset{;; ++ )offsetstatic
{
constexpr :: std6size_t width{};auto
= s slide (::std}span{a,, offset) width;if
( .sempty())break
;print
()s;}
}
判断当前环境是大端序还是小端序
std::endian
- #
include#
includeint
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" ;else
:: std<<cout "mixed-endian\n" ;}
支持数组构造
std::make_shared
- ::
std<shared_ptrfloat[512]=> spA :: stdmake_shared<float[512](>1.0);::
std<shared_ptrdouble[6][2]=> spB :: stdmake_shared<double[6][2](>1.0{,2.0 });::
std<shared_ptr::std<vectorint[>4]=> spC :: stdmake_shared<::std<vectorint[>4](>5{,6 });移除const,varient,引用属性
std::remove_cvref
- #
include#
includeint
main ()::
{
std<<cout :: std<<boolalpha
:: std<is_same_v::std<remove_cvref_tint,>int <<> '\n' <<
:: std<is_same_v::std<remove_cvref_tint&,>int <<> '\n' <<
:: std<is_same_v::std<remove_cvref_tint&&,>int <<> '\n' <<
:: std<is_same_v::std<remove_cvref_tconstint &,>int <<> '\n' <<
:: std<is_same_v::std<remove_cvref_tconstint [2],>int [2]<<> '\n' <<
:: std<is_same_v::std<remove_cvref_tconstint (&)[2],>int [2]<<> '\n' <<
:: std<is_same_v::std<remove_cvref_tint(int),>int (int)<<> '\n' ;}
/*
true
true
true
true
true
true
true
*/
获取原始指针
std::to_address
- #
include#
includeint
main ()::
{
std<shared_ptrinta> (newint 0{});::
std<<cout . aget()<< " " << :: stdto_address()a;//0x493eb0 0x493eb0
return
0 ;}
获取数组最大size
std::ssize & std::size
- #
include#
include#
includeint
main ()::
{
std<vectorint=> v 3 { ,1 ,4 } ;::
std<<cout :: stdsize()v<< '\n' ;int
[ a]= - { 5,10 ,15 } ;::
std<<cout :: stdsize()a<< '\n' ;// since C++20 the signed size (ssize) can avail
auto
= i :: stdssize()v;::
std<<cout "i = " << << i '\n' ;for
( --;i!= i - 1;-- )i:: {
std<<cout [ v]i<< ( ?i ' ' : '\n' );}
::
std<<cout "i = " << << i '\n' ;}
/*
3
3
i = 3
4 1 3
i = -1
*/
该类latch是std::ptrdiff_t类型的向下计数器,可用于同步线程。计数器的值在创建时初始化。线程可能会阻塞在锁存器上,直到计数器减为零。不可能增加或重置计数器,这使得锁存器成为一次性屏障。
std::latch
- #
include#
include#
include#
include#
includeint
main ()struct
{
job const
{
:: std;string name::
std"not worked"string product{};::
std}thread action{;}
[ jobs]= "annika" {{},"buru" {},"chuck" {}};::
std::latch work_done{stdsize()jobs};::
std1latch start_clean_up{};auto
= work [ &](&job) my_job.
{
my_job=product . my_job+name " worked" ;.
work_donecount_down();//执行完毕.
start_clean_upwait();//等待.
my_job=product . my_job+name " cleaned" ;}
;::
std<<cout "Work starting... " ;for
( auto&: job ) jobs.
{
job=action :: std,thread{work:: stdref()job};}
.
work_donewait();//同步等待执行完毕::
std<<cout "done:\n" ;for
( autoconst &: job ) jobs::
{
std<<cout " " << . job<<product '\n' ;}
::
std<<cout "Workers cleaning up... " ;.
start_clean_upcount_down();//通知可以继续了for
( auto&: job ) jobs.
{
job.actionjoin();//join等待线程执行完毕}
::
std<<cout "done:\n" ;for
( autoconst &: job ) jobs::
{
std<<cout " " << . job<<product '\n' ;}
}
/*
Work starting... done:
annika worked
buru worked
chuck worked
Workers cleaning up... done:
annika cleaned
buru cleaned
chuck cleaned
*/
#
std::barrier
-类模板std::barrier提供了一种线程协调机制,该机制最多允许预期数量的线程阻塞,直到预期数量的线程到达屏障。与std::latch不同,屏障是可重用的:一旦到达的线程从屏障阶段的同步点解除阻塞,就可以重用相同的屏障
include#
include#
include#
include#
includeint
main ()const
{
auto = workers "anil" { ,"busara" ,"carl" } ;auto
= on_completion [ ]()noexcept // locking not needed here
{
static
auto = phase "... done\nCleaning up...\n" ;::
std<<cout ; phase=
phase "... done\n" ;// 第一遍执行完后phase就改变了值}
;::
stdsync_pointbarrier (::stdssize()workers,) on_completion;auto
= work [ &](::std)string name::
{
std=string product " " + + name " worked\n" ;::
std<<cout ; product// 3个线程先执行到这儿,然后执行一遍on_completion .
sync_pointarrive_and_wait();=
product " " + + name " cleaned\n" ;::
std<<cout ; product// 然后到这儿,再执行一遍on_completion .
sync_pointarrive_and_wait();// 将此句删除就不会再执行第二遍的on_completion}
;::
std<<cout "Starting...\n" ;::
std<vector::std;thread> threadsfor
( autoconst &: worker ) workers.
{
threadsemplace_back(,work) worker;}
for
( auto&: thread ) threads.
{
threadjoin();}
}
/*
Starting...
anil worked
busara worked
carl worked
... done
Cleaning up...
carl cleaned
busara cleaned
anil cleaned
... done
*/
std::counting_semaphore 简单的说即根据信号量(内部计数器)大于和等于零进行不同的 *** 作,acquire 会让信号量减一,release 会让信号量加一
std::counting_semaphore & std::binary_semaphore
- 大于零,进行 acquire *** 作,信号量减一,不会堵塞线程等于零,进行 acquire *** 作,信号量为零,无法再减,堵塞线程,直到 release *** 作让信号量加一(大于零),重复上一步 #
- std::binary_semaphore 是std::counting_semaphore<1>的别名
include#
include#
include#
include::
std0binary_semaphore
smphSignalMainToThread{},0
smphSignalThreadToMain{};void
ThreadProc ().
{
smphSignalMainToThreadacquire();//得到 -1::
std<<cout "[thread] Got the signal\n" ;using
namespace :: std;literals::
std::this_threadsleep_for(::std::chronoseconds(3));::
std<<cout "[thread] Send the signal\n" ;.
smphSignalThreadToMainrelease();}
int
main ()::
{
stdthrWorkerthread ()ThreadProc;::
std<<cout "[main] Send the signal\n" ;.
smphSignalMainToThreadrelease();//+1.
smphSignalThreadToMainacquire();::
std<<cout "[main] Got the signal\n" ;.
thrWorkerjoin();}
/*
[main] Send the signal
[thread] Got the signal
[thread] Send the signal
[main] Got the signal
*/
std::counting_semaphore
- #
include#
include#
include#
include::
std<counting_semaphore30>
smphSignalMainToThread{},0
smphSignalThreadToMain{};void
ThreadProc1 ().
{
smphSignalMainToThreadacquire();::
std<<cout "[thread] Got the signal1\n" ;using
namespace :: std;literals::
std::this_threadsleep_for(::std::chronoseconds(3));::
std<<cout "[thread] Send the signal1\n" ;.
smphSignalThreadToMainrelease();}
void
ThreadProc2 ().
{
smphSignalMainToThreadacquire();::
std<<cout "[thread] Got the signal2\n" ;using
namespace :: std;literals::
std::this_threadsleep_for(::std::chronoseconds(3));::
std<<cout "[thread] Send the signal2\n" ;.
smphSignalThreadToMainrelease();}
void
ThreadProc3 ().
{
smphSignalMainToThreadacquire();::
std<<cout "[thread] Got the signal3\n" ;using
namespace :: std;literals::
std::this_threadsleep_for(::std::chronoseconds(3));::
std<<cout "[thread] Send the signal3\n" ;.
smphSignalThreadToMainrelease();}
int
main ()::
{
stdthrWorker1thread ()ThreadProc1;::
stdthrWorker2thread ()ThreadProc2;::
stdthrWorker3thread ()ThreadProc3;::
std<<cout "[main] Send the signal\n" ;.
smphSignalMainToThreadrelease(3);.
smphSignalThreadToMainacquire();::
std<<cout "[main] Got the signal\n" ;.
thrWorker1join();.
thrWorker2join();.
thrWorker3join();}
/*
[main] Send the signal
[thread] Got the signal1
[thread] Got the signal2
[thread] Got the signal3
[thread] Send the signal3
[thread] Send the signal2
[thread] Send the signal1
[main] Got the signal
*/
修复std::thread的不足,加入外部主动停止线程
std::jthread
- std::stop_token 类提供是否已经或能对其所关联的 std::stop_source 对象作出停止请求的方法。它实质上是关联停止状态的线程安全视图
- stop_source 类提供发出停止请求的方式
- stop_callback 类模板提供对关联的 std::stop_token 对象注册回调函数的 RAII 对象类型,使得将在 std::stop_token 的关联 std::stop_source 被请求停止时调用回调函数 #
include#
include#
include#
includeint
main ()auto
{
= fn [ &](::std)stop_token stwhile
{
(!.ststop_requested())::
{
std<<cout 1 << "\t" ;::
std::this_threadsleep_for(::std::chronoseconds(1));}
}
;::
stdtdjthread ()fn;::
std::this_threadsleep_for(::std::chronoseconds(3));.
tdrequest_stop();//如果没有这句话在main函数结束时析构td也会自动调用停止return
0 ;}
std::basic_osyncstream 是 std::basic_syncbuf 的便利包装。它提供机制以同步写入同一流的线程
std::basic_osyncstream
- #
include#
includeint
main ()#
{
if1 ::
stdsync_outosyncstream (::std)cout;// std::cout 的同步包装 <<
sync_out "Hello, " ;<<
sync_out "World!" ;<<
sync_out :: std;endl// 注意有冲入,但仍未进行 <<
sync_out "and more!\n" ;#
else::
stdosyncstream(::std)cout<< "Hello, " << "World!" << '\n' ;#
endifreturn
0 ;}
// 转移字符并冲入 std::cout /*
Hello, World!
and more!
*/
std::starts_wit若 string 始于前缀起始则为 true ,否则为 false
std::starts_with & std::ends_with
- #
include#
include#
includetemplate
< typenamePrefixType void>
test_prefix_print (const:: std&string, str) PrefixType prefix::
{
std<<cout '\'' << << str "' starts with '" << << prefix "': " << .
strstarts_with()prefix<< '\n' ;}
int
main ()::
{
stdboolalpha(::std)cout;auto
= helloWorld :: stdstring("hello world");test_prefix_print
(,helloWorld:: stdstring_view("hello"));test_prefix_print
(,helloWorld:: stdstring_view("world"));test_prefix_print
(,helloWorld'h' );test_prefix_print
(,helloWorld'd' );}
/*
'hello world' starts with 'hello': true
'hello world' starts with 'world': false
'hello world' starts with 'h': true
'hello world' starts with 'd': false
*/
上方starts_with换成ends_with,输出结果为:
- std::ends_with 若 string 终于给定后缀则为 true ,否则为 false
'hello world' starts with 'hello': false
'hello world' starts with 'world': true
'hello world' starts with 'h': false
'hello world' starts with 'd': true
- std::string_view #
include#
includeauto
main ()int -> using
{
namespace :: std;literals::
std<<cout
:: std<<boolalpha
"https://cppreference.com" .svstarts_with("http")sv<< ' ' // true <<
"https://cppreference.com" .svstarts_with("ftp")sv<< ' ' // false <<
"C++20" .svstarts_with('C')<< ' ' // true <<
"C++20" .svstarts_with('J')<< ' ' // false <<
:: stdstring_view("string_view").starts_with("string")<< ' ' // true <<
:: stdstring_view("string_view").starts_with("String")<< ' ' // false <<
'\n' ;}
告知编译器 ptr 所指向的对象至少对齐到 N 。实现可用此信息生成更高效的代码
std::assume_aligned
- void
f (int*) pint {
*= p1 :: stdassume_aligned<256(>)p;// 用 p1 而非 p ,以确保从对齐假设受益。
// 然而,若 p 未对齐则程序有未定义行为,无关乎是否使用 p1 。
}
有意令此函数取代 std::bind,不同于 std::bind,它不支持任意参数重排,而且不特别处理嵌套的 bind 表达式或 std::reference_wrapper。另一方面,它注重调用包装对象的值类别,并传播底层调用运算符的异常规定
std::bind_front
- #
include#
includeint
minus (int, aint ) breturn{
- a;b}
struct
S int
{
; valint
minus (int) argconst noexcept return { - val ; arg} }
;int
main ()auto
{
= fifty_minus :: stdbind_front(,minus50 );::
std<<cout fifty_minus ( 3)<< '\n' ;auto
= member_minus :: stdbind_front(&::S,minus50 S{});::
std<<cout member_minus ( 3)<< '\n' ;// 保持 noexcept 说明!
static_assert
(!noexcept (fifty_minus( 3)));static_assert
(noexcept(member_minus( 3)));// 绑定 lambda
auto
= plus [ ](int, aint ) breturn { + a;b} ;auto
= forty_plus :: stdbind_front(,plus40 );::
std<<cout forty_plus (7)<< '\n' ;}
计算整数、浮点或指针 a 与 b 的中点,可以简单地实现为 return a + (b - a) / 2
std::midpoint
- #
include#
include#
include#
includeint
main ()auto
{
= on_pointers [ ](int, iint ) jchar {
const *= text "0123456789" ;char
const *= p + text ; ichar
const *= q + text ; j::
std<<cout "std::midpoint('" << * <<p "', '" << * <<q "'): '" <<
* ::stdmidpoint(,p) q<< "'\n" ;}
;on_pointers
(2,4 );on_pointers
(2,5 );on_pointers
(5,2 );on_pointers
(2,6 );return
0 ;}
/*
std::midpoint('2', '4'): '3'
std::midpoint('2', '5'): '3'
std::midpoint('5', '2'): '4'
std::midpoint('2', '6'): '4'
*/
计算 a+t(b−a) ,即 a 与 b 间参数为 t 的线性内插(或为外插,当 t 落在范围 [0,1] 外时)
std::lerp
- #
include#
includeint
main ()float
{
= a10.0f,= b20.0f;::
std<<cout "a=" << << a ", " << "b=" << << b '\n' <<
"mid point=" << :: stdlerp(,a,b0.5f)<< '\n' <<
:: std<<boolalpha ( ==a :: stdlerp(,a,b0.0f))<< ' ' <<
:: std<<boolalpha ( ==b :: stdlerp(,a,b1.0f))<< '\n' ;return
0 ;}
/*
a=10, b=20
mid point=15
true true
*/
std::is_bounded_array检查 T 是否为拥有已知边界的数组类型。若 T 是有已知边界的数组则提供等于 true 的成员常量 value 。否则 value 等于 false
std::is_bounded_array & std:: is_unbounded_array
- std:: is_unbounded_array 正好相反 #
include#
includeclass
A } {;int
main ()::
{
std<<cout :: std;boolalpha::
std<<cout :: std<is_bounded_array_v<<A> '\n' ;// false ::
std<<cout :: std<is_bounded_array_v[A]<<> '\n' ;// false ::
std<<cout :: std<is_bounded_array_v[A3]<<> '\n' ;// true ::
std<<cout :: std<is_bounded_array_vfloat<<> '\n' ;// false ::
std<<cout :: std<is_bounded_array_vint<<> '\n' ;// false ::
std<<cout :: std<is_bounded_array_vint[]<<> '\n' ;// false ::
std<<cout :: std<is_bounded_array_vint[3]<<> '\n' ;// true ::
std<<cout :: std;boolalpha::
std<<cout :: std<is_unbounded_array_v<<A> '\n' ;// false ::
std<<cout :: std<is_unbounded_array_v[A]<<> '\n' ;// true ::
std<<cout :: std<is_unbounded_array_v[A3]<<> '\n' ;// false ::
std<<cout :: std<is_unbounded_array_vfloat<<> '\n' ;// false ::
std<<cout :: std<is_unbounded_array_vint<<> '\n' ;// false ::
std<<cout :: std<is_unbounded_array_vint[]<<> '\n' ;// true ::
std<<cout :: std<is_unbounded_array_vint[3]<<> '\n' ;// false return
0 ;}
范围(ranges):是“项目集合”或“可迭代事物”的抽象。最基本的定义只需要存在begin()和end()在范围内。Range 代表一串元素, 或者一串元素中的一段类似 begin/end 对
std::ranges
- 更多详情请查看:std::ranges #
include#
includeint
main ()auto
{
const = ints 0 {,1,2,3,4,5};auto
= even [ ](int) ireturn { 0 == % i 2 ;} ;auto
= square [ ](int) ireturn { * i ; i} ;// 组合视图的“管道”语法:
for
( int: i | ints :: std::viewsfilter()even| :: std::viewstransform()square):: {
std<<cout << i ' ' ;}
::
std<<cout '\n' ;// 传统的“函数式”组合语法:
for
( int: i :: std::viewstransform(::std::viewsfilter(,ints) even,) square):: {
std<<cout << i ' ' ;}
}
// 0 4 16 从容器中擦除所有比较等于 value 的元素,从容器中擦除所有满足 pred 的元素
std::erase & std::erase_if
- #
include#
include#
includevoid
print_container (const:: std<vectorchar&>) cfor
{
( auto: x ) c:: {
std<<cout << x ' ' ;}
::
std<<cout '\n' ;}
int
main ()::
{
std<vectorcharcnt> (10);::
stdiota(.cntbegin(),. cntend(),'0' );::
std<<cout "Init:\n" ;print_container
()cnt;// 0 1 2 3 4 5 6 7 8 9 auto
= erased :: stderase(,cnt'3' );::
std<<cout "Erase \'3\':\n" ;print_container
()cnt;// 0 1 2 4 5 6 7 8 9 ::
stderase_if(,cnt[ ](char) xreturn { ( -x '0' )% 2 == 0 ;} );::
std<<cout "Erase all even numbers:\n" ;print_container
()cnt;// 1 5 7 9::
std<<cout "In all " << << erased " even numbers were erased.\n" ;// 5}
提供数个数学常数,详情请查看:std::numbers
std::numbers
- #
include#
include#
include#
include#
include#
includeint
main ()using
{
namespace :: std;numbers::
std<<cout
:: stdpow(,e) ln2/ 2 << ' ' <<
:: stdpow(::stdcosh()pi,2 )- :: stdpow(::stdsinh()pi,2 )<< ' ' <<
:: stdsqrt()pi* << inv_sqrtpi ' ' <<
:: stdpow(*sqrt2 , sqrt32 )/ 6 << ' ' <<
* sqrt3 << inv_sqrt3 ' ' <<
* log2e << ln2 ' ' <<
* log10e << ln10 ' ' <<
* pi << inv_pi ' ' <<
* phi - phi << phi '\n' ;auto
= egamma_aprox [ ]long {
double = s 0 ,= m 2.0 ;for
( unsigned= c 2 ;!= c 1'000'000 ;++ ,c++ )mconst {
long double = t :: stdriemann_zeta()m/ ; m(
&c 1 )== 0 ? += s : t -= s ; t}
return
; s}
;::
std<<cout :: std<<fixed ( <egamma_vlongdouble -> egamma_aprox ())<< '\n' ;constexpr
:: std"0.577215664901532860606512090082402"string_view γ {};::
std<<cout
<< "γ as egamma_v = "
:: stdsetprecision(::std<numeric_limitsfloat::>+digits10 1 )<<
< egamma_vfloat<<> '\n' <<
<< "γ as egamma_v = "
:: stdsetprecision(::std<numeric_limitsdouble::>+digits10 1 )<<
< egamma_vdouble<<> '\n' <<
<< "γ as egamma_v = "
:: stdsetprecision(::std<numeric_limitslongdouble ::>+digits10 1 )<<
< egamma_vlongdouble <<> '\n' <<
"γ with " << . γlength()- 1 << " digits precision = " << << γ '\n' ;return
0 ;}
/*
1 1 1 1 1 1 1 1 1
0.000001
γ as egamma_v = 0.5772157
γ as egamma_v = 0.5772156649015329
γ as egamma_v = 0.5772156649015328606
γ with 34 digits precision = 0.577215664901532860606512090082402
*/
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)