C++17常用特性

2023-01-06  本文已影响0人  wolfaherd

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

__has_include
execution
memory_resource
缓存线接口
scoped_lock
optional

核心语言特性

u8'c-char '

{
  init_statement
  attr(optional) if constexpr(optional) ( condition )
    statement-true
  else
    statement-false
}
  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修饰的作用类似于宏替换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 (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");
}
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

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

#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 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';

用作消除并行算法重载歧义的唯一类型,可以选择执行策略类型: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库提供了对文件系统及其组件(如路径、常规文件和目录)执行操作的工具。

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

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

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

类型安全的有区别的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';
    }

标准库特性

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

这个函数对象为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
*/
#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是一种独特的类型,它实现了c++语言定义中指定的字节概念。

判断类型是否一致

#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";
}

检查是否可交换

检查函数和参数是否匹配

判断是否是数组

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

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

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

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

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

#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
*/

求最大公因数

求最小公倍数

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

用于合并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
*/

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

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

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

获取3D向量的长度。

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

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

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

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

上一篇 下一篇

猜你喜欢

热点阅读