C++17常用特性

需要记忆的(面试六脉神剑)

__has_include
execution
memory_resource
缓存线接口
scoped_lock
optional

核心语言特性

  • UTF-8字符文字

u8'c-char '

  • constexpr可以放在编译期用作条件判断
{
  init_statement
  attr(optional) if constexpr(optional) ( condition )
    statement-true
  else
    statement-false
}
  • lambda表达式会默认尝试转换为constexpr
  auto Fwd = [](int(*fp)(int), auto a){ return fp(a); };
  auto C = [](auto a){ return a; };
  static_assert(Fwd(C, 3) == 3);  // OK
 
  auto NC = [](auto a){ static int s; return a; };
  static_assert(Fwd(NC, 3) == 3); // error: no specialization can be
                                // constexpr because of static s
  • 变量可以用inline修饰

变量被多个源文件外部链接必须是inline,inline修饰的作用类似于宏替换constexpr

// variable with external linkage included in multiple source files must be inline
inline std::atomic<int> counter(0);
  • 结构化绑定声明

将指定的名称绑定到初始化式的子对象或元素。

int a[2] = {1, 2};
 
auto [x, y] = a;    // creates e[2], copies a into e,
                    // then x refers to e[0], y refers to e[1]
auto& [xr, yr] = a; // xr refers to a[0], yr refers to a[1]
  • if和switch可以初始化参数
if (auto it = m.find(10); it != m.end()) { return it->second.size(); }
  • 临时实例化

任何完整类型T的prvalue都可以转换为相同类型T的xvalue。这种转换通过以临时对象作为结果对象对prvalue求值来初始化一个T类型的临时对象,并生成一个表示临时对象的xvalue。如果T是类类型的类或数组,则它必须具有可访问且不可删除的析构函数。

struct S { int m; };
int i = S().m; // member access expects glvalue as of C++17;
               // S() prvalue is converted to xvalue
  • 折叠表达式

(E op ...)等价于(E1 op (... op (EN-1 op EN)))
(…op E)等价于(((E1 op E2) op…)op EN)
(E op…op I)等价于(E1 op (... op (EN−1 op (EN op I))))
(I op ... op E)等价于((((I op E1) op E2) op ...) op EN)

template<typename... Args>
void printer(Args&&... args)
{
    (std::cout << ... << args) << '\n';
}
int main()
{
    printer(1, 2, 3, "abc");
}
  • auto声明非类型模版参数
template<auto n>
struct B { /* ... */ };
 
B<5> b1;   // OK: non-type template parameter type is int
B<'a'> b2; // OK: non-type template parameter type is char
B<2.5> b3; // error (until C++20): non-type template parameter type cannot be double
  • __has_include

检查头文件或源文件是否可用。

#if __has_include(<optional>)
#  include <optional>
#  define has_optional 1
   template<class T> using optional_t = std::optional<T>;
#elif __has_include(<experimental/optional>)
#  include <experimental/optional>
#  define has_optional -1
   template<class T> using optional_t = std::experimental::optional<T>;
#else
#  define has_optional 0
#  include <utility>
  • any

类any描述了用于任何复制构造类型的单个值的类型安全容器。

 // any type
    std::any a = 1;
    std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';
    a = 3.14;
    std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';
    a = true;
    std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';
  • excution

用作消除并行算法重载歧义的唯一类型,可以选择执行策略类型:sequenced_policy(顺序执行),parallel_policy(并行执行),parallel_unsequenced_policy(非顺序并行执行)。

int x = 0;
std::mutex m;
int a[] = {1,2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) {
  std::lock_guard<std::mutex> guard(m);
  ++x; // correct
});
  • filesystem

filesystem库提供了对文件系统及其组件(如路径、常规文件和目录)执行操作的工具。

  • std::pmr::memory_resource

封装内存资源的类的抽象接口
派生出:
synchronized_pool_resource(线程安全),
unsynchronized_pool_resource(线程不安全),
monotonic_buffer_resource(特殊用途:用于非常快速的内存分配,在这种情况下,内存用于构建几个对象,然后立即释放所有内存。)

  • optional

选择性保存一个对象的包装器

// std::nullopt can be used to create any (empty) std::optional
auto create2(bool b) {
    return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
  • variant

类型安全的有区别的union

std::variant<int, float> v, w;
    v = 42; // v contains int
    int i = std::get<int>(v);
    assert(42 == i); // succeeds
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line
    w = v; // same effect as the previous line
 
//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1
 
    try {
        std::get<float>(w); // w contains int, not float: will throw
    }
    catch (const std::bad_variant_access& ex) {
        std::cout << ex.what() << '\n';
    }

标准库特性

  • weak_from_this

返回一个std::weak_ptr<T>,通过所有引用this的现有std::shared_ptr跟踪this的所有权
这是private mutable weak_ptr成员的副本,该成员是enable_shared_from_this的一部分。

  • owner_less

这个函数对象为std::weak_ptr和std::shared_ptr提供了基于所有者的(而不是基于值的)混合类型排序。只有当两个智能指针都为空或共享所有权时,才会比较等效,即使get()获得的原始指针的值不同(例如,当它们指向同一对象中的不同子对象)。

#include <iostream>
#include <memory>
#include <set>
int main () {
   int * p = new int (10);
   std::shared_ptr<int> a (new int (20));
   std::shared_ptr<int> b (a,p);
   std::set < std::shared_ptr<int> > value_based;
   std::set < std::shared_ptr<int>, std::owner_less<std::shared_ptr<int>> > owner_based;
   value_based.insert (a);
   value_based.insert (b);
   owner_based.insert (a);
   owner_based.insert (b);
   std::cout << "value_based.size() is " << value_based.size() << '\n';
   std::cout << "owner_based.size() is " << owner_based.size() << '\n';
   delete p;
   return 0;
}
/*输出
value_based.size() is 2
owner_based.size() is 1
*/
  • shared_ptr支持数组
#include <cstddef>
#include <memory>
#include <iostream>
int main() {
    const std::size_t arr_size = 10;
    std::shared_ptr<int[]> pis(new int[10]{0,1,2,3,4,5,6,7,8,9});
    for (std::size_t i = 0; i < arr_size; i++){
        std::cout << pis[i] << ' ';
    }
}
  • byte

byte是一种独特的类型,它实现了c++语言定义中指定的字节概念。

  • conjunction

判断类型是否一致

#include <iostream>
#include <type_traits>
 
// func is enabled if all Ts... have the same type as T
template<typename T, typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...>>
func(T, Ts...)
{
    std::cout << "all types in pack are T\n";
}
  • is_swappable

检查是否可交换

  • is_invocable

检查函数和参数是否匹配

  • is_aggregate

判断是否是数组

  • clamp
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi );

如果v < lo,返回lo。如果hi小于v,返回hi。其他情况下返回v。

  • reduce

求和,可以并行计算(std::execution::par)

  • inclusive_scan

扫描得到前面元素的累加或累乘值

  • exclude_scan

扫描得到前面元素的累加或累乘值,需设置初始值,并且最后一个元素不参与计算。

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
 
int main()
{
  std::vector data {3, 1, 4, 1, 5, 9, 2, 6};
 
  std::cout << "exclusive sum: ";
  std::exclusive_scan(data.begin(), data.end(),
              std::ostream_iterator<int>(std::cout, " "),
              0);
  std::cout << "\ninclusive sum: ";
  std::inclusive_scan(data.begin(), data.end(),
              std::ostream_iterator<int>(std::cout, " "));
 
  std::cout << "\n\nexclusive product: ";  
  std::exclusive_scan(data.begin(), data.end(),
              std::ostream_iterator<int>(std::cout, " "),
              1, std::multiplies<>{});            
  std::cout << "\ninclusive product: ";
  std::inclusive_scan(data.begin(), data.end(),
              std::ostream_iterator<int>(std::cout, " "),
              std::multiplies<>{});           
}
/*输出
exclusive sum: 0 3 4 8 9 14 23 25 
inclusive sum: 3 4 8 9 14 23 25 31 
 
exclusive product: 1 3 3 12 12 60 540 1080 
inclusive product: 3 3 12 12 60 540 1080 6480
*/
  • gcd

求最大公因数

  • lcm

求最小公倍数

  • extract

可用于在不重新分配的情况下修改map/set的key值。

  • merge

用于合并map/set,如果元素的key在新容器已存在,则保留该元素,否则将其插入到新容器中,旧容器不再保留该元素。

#include <map>
#include <iostream>
#include <string>
 
int main()
{
  std::map<int, std::string> ma {{1, "apple"}, {5, "pear"}, {10, "banana"}};
  std::map<int, std::string> mb {{2, "zorro"}, {4, "batman"}, {5, "X"}, {8, "alpaca"}};
  std::map<int, std::string> u;
  u.merge(ma);
  std::cout << "ma.size(): " << ma.size() << '\n';
  u.merge(mb);
  std::cout << "mb.size(): " << mb.size() << '\n';
  std::cout << "mb.at(5): " << mb.at(5) << '\n';
  for(auto const &kv: u)
    std::cout << kv.first << ", " << kv.second << '\n';
}
/*输出
ma.size(): 0
mb.size(): 1
mb.at(5): X
1, apple
2, zorro
4, batman
5, pear
8, alpaca
10, banana
*/
  • try_emplace

如果容器中没有具有该键的元素,则插入一个带有键k和值的新元素到容器中。

  • insert_or_assign

如果容器中已经存在一个等价于k的键,则将std::forward<M>(obj)赋值给与键k对应的mapped_type。如果键不存在,则像通过insert一样插入新值,从value_type(k, std::forward<M>(obj))构造它。

  • 连续迭代器(LegacyContiguousIterator)

不仅逻辑上连续,在物理上也连续。

  • hypot支持3D

获取3D向量的长度。

  • 缓存线接口

hardware_destructive_interference_size
hardware_constructive_interference_size
这些常量提供了一种可移植的方式来访问L1数据缓存线大小。

  • uncaught_exceptions

检测当前线程中有多少异常已经抛出或重新抛出,但尚未输入匹配的catch子句。

  • atomic<T>::is_always_lock_free

如果此原子类型总是无锁,则为true;如果从不或有时无锁,则为false。

  • scoped_lock

类scoped_lock是一个互斥锁包装器,它提供了一种方便的RAII风格的机制,用于在作用域块期间拥有零个或多个互斥锁。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,001评论 6 537
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,786评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,986评论 0 381
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,204评论 1 315
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,964评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,354评论 1 324
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,410评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,554评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,106评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,918评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,093评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,648评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,342评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,755评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,009评论 1 289
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,839评论 3 395
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,107评论 2 375

推荐阅读更多精彩内容