0%

可变参数模板的需求

可变参数模板有助于解决在编译时求值类型安全,不需要宏,不需要显式指定 参数的数量,可以编写可变参数函数模板和可变参数类模板。此外,也有可变参数变量模板和可变 参数别名模板。

可变参数函数模板

可变参数模板以两种方式使用省略号。在参数名称的左侧,表示参数包,在参数名称的右侧,将参数包扩展为单独的名称。

1
2
3
4
5
6
7
8
9
10
template <typename T> 
T min(T a, T b)
{
return a < b ? a : b;
}
template <typename T, typename... Args>
T min(T a, Args... args)
{
return min(a, min(args...));
}
  • 要在模板参数列表中指定一组参数,如 typename... Args,这称为模板参数包。可以为类型模板、非类型模板和双重模板参数定义的模板参数包。
  • 函数参数列表中指定一组参数,如 Args...args,这称为函数参数包。
  • 函数体中展开包,如在 args... 中,可在 min(args...) 中看到,这称为参数包展开。这种展开的结果是一个由零个或多个值 (或表达式) 组成的逗号分隔列表。

参数包

  • sizeof... 计算参数包的大小,返回 std::size_t 类型的 constexpr 值。

可变参数类模板

折叠表达式

折叠方式 语法 展开方式
一元右折叠 (pack op …) (arg1 op (… op (argN-1 op argN)))
一元左折叠 (… op pack) (((arg1 op arg2) op …) op argN)
二元右折叠 (pack op … op init) (arg1 op (… op (argN-1 op (argN op init))))
二元左折叠 (init op … op pack) ((((init op arg1) op arg2) op …) op argN)
  • 一元折叠中,若参数包不包含任何元素,则只允许使用某些操作符。下表列出了这些值,以及 空参数包的值:

    操作符 空参数包的值
    && (逻辑 AND) true
    || (逻辑 OR) false
    , (逗号操作符) void()

可变参数别名模板

可变参数变量模板

install(CODE)execute_process 配合

确保 WORKING_DIRECTORY 存在

示例代码:

1
2
3
4
5
set(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/export)
install(CODE "
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory folder
WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX})
")

注意确保 CMAKE_INSTALL_PREFIX 存在,可能执行这段代码时还没有 install target 导致 CMAKE_INSTALL_PREFIX 还没有生成。

阅读全文 »

存储和加载指令

ldr 指令寻址之1: 地址偏移模式 (unsigned offset)

1
LDR Xd, [Xn, $offset]

首先在 Xn 寄存器的内容上加上一个 offset 偏移量后作为内存地址,加载此地址的内容到 Xd 寄存器。

ldr 指令寻址之2: 变基模式

  • 前变基模式(pre-index 模式): 先更新偏移地址然后再访问内存。
  • 后变基模式(post-index 模式):先访问内存地址然后再更新偏移地址。
1
2
3
LDR X0, [X1, #8]! // 前变基模式。先更新X1 的值为 X1+8,然后义新的X1值为地址,加载内存的值到X0

LDR X0, [X1], #8 // 后变基模式。以x1的值为地址,加载该内存地址的值到X0,然后在更新X1寄存器为X1+8

ldr 指令寻址之3: 标签(literal

PC + label offset

ldr 伪指令

1
LDR x7, =MY_LABEL

move 指令

  • 16位立即数
  • 16立即数左移16,32,48位

多字节加载和存储指令 ldp 和stp

ARM 指令概要介绍

  • A64 指令集只能运行在 aarch64 环境中
  • 所有的A64汇编指令都是 32bits
  • A64 支持全部是大写或者全部是小写的书写方式

寄存器名:

Name Size Encoding Description
Wn 32 bits 0-30 Genral-purpose register 0-30
Xn 64 bits 0-30 Genral-purpose register 0-30
WZR 32 bits 31 Zero register
XZR 64 bits 31 Zero register
WPS 32 bits 31 Current stack pointer
SP 64 bits 31 Current stack pointer
阅读全文 »

使用场景

当我们在对象函数中需要返回或者使用自己的 shared_ptr 指针时,该怎么办呢?常见的错误写法如下:用不安全的表达式试图获得 thisshared_ptr 对象, 但可能会导致 this 被多个互不知晓的所有者析构.

1
2
3
4
5
6
7
struct Bad
{
std::shared_ptr<Bad> getptr() {
return std::shared_ptr<Bad>(this);
}
~Bad() { std::cout << "Bad::~Bad() called\n"; }
};
1
2
3
4
5
{
std::shared_ptr<Bad> bp1 = std::make_shared<Bad>();
std::shared_ptr<Bad> bp2 = bp1->getptr();
std::cout << "bp2.use_count() = " << bp2.use_count() << '\n';
} // UB: Bad 对象将会被删除两次

正确写法是将定义对象公开继承 enable_shared_from_this:

1
2
3
4
5
6
class Good: public std::enable_shared_from_this<Good> // 注意:继承
{
std::shared_ptr<Good> getptr() {
return shared_from_this();
}
};
阅读全文 »

Item 21: Always have comparison functions return false for equal values.

严格弱序( strict weak ordering )

先补充下严格弱序的概念: 对两个变量 xy

  • x > y 等同于 y < x
  • x == y 等同于 !(x < y) && !(x > y)

要想严格弱序,就需要遵循如下规则:

  • 每个变量值必须等于其本身(irreflexivity):x < x 永远不能为 true
  • 不对称性(asymmetry):如果 x < y,那么 y < x 就不能为 true
  • 有序性必须可传递性:如果 x < y 并且 y < z,那么 x < z
  • 值相同必须具有可传递性:如果 x == y 并且 y == z,那么 x == z
阅读全文 »

介绍

结构

什么是Reactor模式

Reactor模式结构

  • Handles:
  • Synchronous Event Demultiplexer
  • Initiation Dispatcher
  • Event Handler
  • Concrete Event Handler

Reactor模式模块之间的交互

Reactor模式实现

Reactor模式优点

Reactor模式的缺点

  • Efficiency
  • Programming simplicity
  • Portability

Item9. Choose carefully among easing options.

一、删除特定值

  1. 对于 vectorstringdeque

    最好使用 erase-remove习惯用法:

    1
    c.erase(remove(c.begin(), c.end(), 1963, c.end()));
  2. 对于 list 容器

    直接使用 remove 方法:

    1
    c.remove(1963);
  3. 对于标准关联容器

    直接使用 erase 方法:

    1
    c.erase(1963)
阅读全文 »

介绍

Disk Arbitration framework 是一个基于 Core Foundation 的低级框架。会在磁盘出现和消失时通知您的应用程序,并让您的应用程序影响该过程。借助 Disk Arbitration,我们可以:

  • 检测何时出现新磁盘
  • 阻止挂载
  • 使用不同的标志或在不同的安装点上安装卷
  • 卸载卷
  • 观察卷的变化
阅读全文 »