C++20新特性

C++20新特性,第1张

语言特性 __has_cpp_attribute
  • 检查是否存在由属性标记命名的属性,例如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
  • 新增的宽字符串
[[no_unique_address]]
  • 适用于在不是位字段的非静态数据成员的声明中声明的名称,编译器可以优化它以不占用空间
#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
    */
    

    欢迎分享,转载请注明来源:内存溢出

    原文地址:https://54852.com/langs/1296049.html

    (0)
    打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
    上一篇 2022-06-10
    下一篇2022-06-10

    发表评论

    登录后才能评论

    评论列表(0条)

      保存