基于 boost 1.82

timer 计时器

过去老的 boost/timer.hpp 已经废弃了,目前推荐使用的是 boost/timer/timer.hpp, 主要包括下面了2个类

classdetail
boost::timer::cpu_timer计时器
boost::timer::auto_cpu_timer计时器,基于cpu_timer实现,在析构的时候输出耗时
1
2
3
4
5
6
7
struct cpu_times {
nanosecond_type wall; // 挂钟时间
nanosecond_type user; // 用户时间
nanosecond_type system; // 系统时间

void clear() {wall = user = system = 0LL; }
};

默认的输出格式为下:

“%w s wall, %u s user + %s s system = %t s CPU (%p%)\n”

formatmeaning
%wtimes.wall
%utimes.user
%stimes.system
%ttimes.user + times.system
%pThe percentage of times.wall represented by times.user + times.system

来个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <boost/timer/timer.hpp>
#include <cmath>
#include <iostream>

using namespace std;
using namespace boost;

int main() {
timer::cpu_timer t;
timer::auto_cpu_timer auto_timer(6, "%ws real time\n");

for (long i = 0; i < 100000000; ++i)
auto _ = sqrt(i * i); // spend some time

cout << t.format(2, "%us user + %ss system = %ts(%p%)") << endl;

t.start();
for (long i = 0; i < 100000000; ++i)
auto _ = sqrt(i * i); // spend some time
cout << t.format(2, "%us user + %ss system = %ts(%p%)") << endl;

return 0;
}

split

头文件为 boost/algorithm/string/split.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <set>

int main(int argc, char *argv[]) {
std::string str = "123,,345,qwe;adq,345";
std::set<std::string> st;
boost::split(st, str, boost::is_any_of(",; "), boost::token_compress_on);
for_each(st.begin(), st.end(), [](const std::string& x) {std::cout << "[" << x << "]\n";});

return 0;
}

默认为 token_compress_off: 表示遇见多个token时候,不合并成一个token, 这时候,,分割后,会多一个空string,表示2个逗号中间的空string

需要链接的库: libboost_system (通常自动链接)

circular_buffer 环形缓冲区

Boost.Circular_buffer 提供了固定大小的环形缓冲区,当缓冲区满时自动覆盖最旧的数据。C++23 标准库中没有类似功能。

头文件: boost/circular_buffer.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <boost/circular_buffer.hpp>
#include <iostream>

int main() {
// 创建容量为 5 的环形缓冲区
boost::circular_buffer<int> cb(5);

// 添加元素
for (int i = 0; i < 7; ++i) {
cb.push_back(i);
std::cout << "Added " << i << ", size: " << cb.size()
<< ", capacity: " << cb.capacity() << "\n";
}

// 输出内容
std::cout << "Contents: ";
for (const auto& item : cb) {
std::cout << item << " ";
}
std::cout << "\n";

// 访问元素
std::cout << "Front: " << cb.front() << "\n";
std::cout << "Back: " << cb.back() << "\n";
std::cout << "cb[2]: " << cb[2] << "\n";

// 插入到指定位置
cb.insert(cb.begin() + 2, 99);

std::cout << "After insert: ";
for (const auto& item : cb) {
std::cout << item << " ";
}
std::cout << "\n";

// 弹出元素
cb.pop_front();

std::cout << "After pop_front: ";
for (const auto& item : cb) {
std::cout << item << " ";
}
std::cout << "\n";

return 0;
}

需要链接的库: header-only

heap 优先队列

Boost.Heap 提供了多种优先队列实现,包括二叉堆、斐波那契堆等。C++23 只有 std::priority_queue,功能有限。

头文件: boost/heap/priority_queue.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <boost/heap/priority_queue.hpp>
#include <iostream>
#include <string>

int main() {
// 使用 priority_queue(二叉堆)
boost::heap::priority_queue<int> pq;

// 插入元素
pq.push(5);
pq.push(3);
pq.push(8);
pq.push(1);
pq.push(4);

std::cout << "Priority queue size: " << pq.size() << "\n";
std::cout << "Top element: " << pq.top() << "\n";

// 弹出元素
while (!pq.empty()) {
std::cout << "Pop: " << pq.top() << "\n";
pq.pop();
}

// 使用自定义比较器
auto cmp = [](const std::string& a, const std::string& b) {
return a.length() < b.length(); // 按长度排序
};

boost::heap::priority_queue<std::string, boost::heap::compare<decltype(cmp)>>
strPq(cmp);

strPq.push("hello");
strPq.push("hi");
strPq.push("hey there");
strPq.push("a");

std::cout << "\nString priority queue (by length):\n";
while (!strPq.empty()) {
std::cout << "Pop: " << strPq.top() << "\n";
strPq.pop();
}

// 使用 fibonacci_heap(更好的合并性能)
boost::heap::fibonacci_heap<int> fibHeap;
fibHeap.push(10);
fibHeap.push(20);
fibHeap.push(5);

std::cout << "\nFibonacci heap top: " << fibHeap.top() << "\n";

return 0;
}

需要链接的库: header-only

string_algo 字符串算法

Boost.String_algo 提供了丰富的字符串处理算法,比 STL 的字符串操作更强大。

头文件: boost/algorithm/string.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <vector>

int main() {
std::string text = " Hello, World! ";

// 大小写转换
std::string upper = boost::to_upper_copy(text);
std::string lower = boost::to_lower_copy(text);
std::cout << "Upper: " << upper << "\n";
std::cout << "Lower: " << lower << "\n";

// 去除空白
std::string trimmed = boost::trim_copy(text);
std::cout << "Trimmed: " << trimmed << "\n";

// 查找和替换
std::string replaced = boost::replace_all_copy(text, "World", "Boost");
std::cout << "Replaced: " << replaced << "\n";

// 查找子串
if (boost::contains(text, "Hello")) {
std::cout << "Contains 'Hello'\n";
}

// 检查前缀和后缀
if (boost::starts_with(text, " ")) {
std::cout << "Starts with spaces\n";
}

if (boost::ends_with(text, " ")) {
std::cout << "Ends with spaces\n";
}

// 分割字符串
std::string data = "apple,banana,orange";
std::vector<std::string> fruits;
boost::split(fruits, data, boost::is_any_of(","));

std::cout << "Fruits:\n";
for (const auto& fruit : fruits) {
std::cout << " " << fruit << "\n";
}

// 连接字符串
std::string joined = boost::join(fruits, ";");
std::cout << "Joined: " << joined << "\n";

// 删除字符
std::string removed = boost::erase_all_copy(text, " ");
std::cout << "Removed spaces: " << removed << "\n";

// 查找第N个位置
std::string str = "a-b-c-d-e";
size_t pos = boost::find_nth(str, "-", 2).begin() - str.begin();
std::cout << "3rd '-' at position: " << pos << "\n";

// 查找所有匹配
std::vector<boost::iterator_range<std::string::iterator>> matches;
boost::find_all(matches, str, "-");
std::cout << "Found " << matches.size() << " '-' characters\n";

return 0;
}

需要链接的库: header-only

tokenizer 字符串分词器

Boost.Tokenizer 提供了灵活的字符串分词功能,支持多种分词策略。

头文件: boost/tokenizer.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <boost/tokenizer.hpp>
#include <iostream>
#include <string>

int main() {
// 使用字符分隔符
std::string str1 = "Hello,World,Boost,C++";
boost::char_separator<char> sep(",");
boost::tokenizer<boost::char_separator<char>> tokens1(str1, sep);

std::cout << "Character separator:\n";
for (const auto& token : tokens1) {
std::cout << " " << token << "\n";
}

// 使用空格分隔(跳过连续空格)
std::string str2 = "Hello World Boost";
boost::char_separator<char> space_sep(" ", "", boost::drop_empty_tokens);
boost::tokenizer<boost::char_separator<char>> tokens2(str2, space_sep);

std::cout << "\nSpace separator (drop empty):\n";
for (const auto& token : tokens2) {
std::cout << " " << token << "\n";
}

// 使用 escaped_list_separator(类似 CSV)
std::string str3 = "1,\"Hello, World\",3.14";
boost::escaped_list_separator<char> els("\\", ",", "\"");
boost::tokenizer<boost::escaped_list_separator<char>> tokens3(str3, els);

std::cout << "\nEscaped list separator (CSV-like):\n";
for (const auto& token : tokens3) {
std::cout << " " << token << "\n";
}

// 使用 offset_separator(固定宽度)
std::string str4 = "1234567890";
int offsets[] = {3, 3, 4};
boost::offset_separator off_sep(offsets, offsets + 3);
boost::tokenizer<boost::offset_separator> tokens4(str4, off_sep);

std::cout << "\nOffset separator (fixed width):\n";
for (const auto& token : tokens4) {
std::cout << " " << token << "\n";
}

return 0;
}

需要链接的库: header-only

lockfree 无锁数据结构

Boost.Lockfree 提供了无锁队列、栈等数据结构,用于高并发场景。C++23 标准库中没有类似功能。

头文件: boost/lockfree/queue.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <boost/lockfree/queue.hpp>
#include <boost/lockfree/stack.hpp>
#include <iostream>
#include <thread>
#include <vector>

int main() {
// 无锁队列
boost::lockfree::queue<int> q(100); // 固定大小

// 生产者线程
auto producer = [&]() {
for (int i = 0; i < 1000; ++i) {
while (!q.push(i)) {
// 队列满,重试
}
}
};

// 消费者线程
std::atomic<int> sum{0};
auto consumer = [&]() {
int value;
while (true) {
if (q.pop(value)) {
sum += value;
} else {
// 队列空,检查是否完成
if (sum.load() >= 499500) { // 0+1+...+999 = 499500
break;
}
}
}
};

std::thread t1(producer);
std::thread t2(consumer);

t1.join();
t2.join();

std::cout << "Sum: " << sum << "\n";

// 无锁栈
boost::lockfree::stack<int> s(100);

for (int i = 0; i < 10; ++i) {
s.push(i);
}

std::cout << "Stack contents:\n";
int value;
while (s.pop(value)) {
std::cout << value << " ";
}
std::cout << "\n";

return 0;
}

需要链接的库: header-only

pool 内存池

Boost.Pool 提供了高性能的内存池实现,适用于频繁分配/释放小对象的场景。

与 jemalloc/tcmalloc 的关系

你可能会问:“有了 jemalloc/tcmalloc 这类高性能 malloc,还需要 Boost.Pool 吗?”

答案是:jemalloc 解决的是通用内存分配问题,Pool 解决的是对象池语义问题。二者不在同一层面:

特性jemalloc/tcmallocBoost.Pool
层级系统级 malloc 替换应用级对象池
分配粒度通用内存块固定大小对象
构造/析构只分配内存可以分离构造和分配
批量释放不支持支持 purge_memory() 一次性释放整个池
对象重用释放的对象回到池中复用

Pool 相比 jemalloc 的优势场景

  1. 链表/树节点管理:需要频繁 new/delete 节点,但生命周期跟随整个数据结构
  2. 游戏对象池:子弹、粒子等对象需要快速创建销毁,且经常批量清除
  3. 内存和构造分离:只想分配原始内存,稍后或选择性构造对象
  4. 避免频繁系统调用:即使 jemalloc 也有 overhead,Pool 完全在用户态

简单说:jemalloc 让 new/delete 更快,Pool 让你少用甚至不用 new/delete

头文件: boost/pool/object_pool.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <boost/pool/object_pool.hpp>
#include <iostream>
#include <vector>

class Node {
public:
int value;
Node* next;

Node(int v) : value(v), next(nullptr) {}
~Node() { std::cout << "Node " << value << " destroyed\n"; }
};

int main() {
// object_pool - 对象池
boost::object_pool<Node> nodePool;

std::cout << "Creating nodes from pool:\n";
Node* n1 = nodePool.construct(1);
Node* n2 = nodePool.construct(2);
Node* n3 = nodePool.construct(3);

n1->next = n2;
n2->next = n3;

std::cout << "Nodes linked: " << n1->value << " -> "
<< n1->next->value << " -> " << n2->next->value << "\n";

// 手动释放
nodePool.destroy(n1);
nodePool.destroy(n2);
nodePool.destroy(n3);

std::cout << "\nCreating more nodes:\n";
std::vector<Node*> nodes;
for (int i = 0; i < 1000; ++i) {
nodes.push_back(nodePool.construct(i));
}

std::cout << "Pool memory used: " << nodePool.get_memory_usage() << "\n";
std::cout << "Pool size: " << nodePool.get_free_count() << "\n";

// 清空池
nodes.clear();
nodePool.purge_memory();

std::cout << "After purge, free count: " << nodePool.get_free_count() << "\n";

return 0;
}

需要链接的库: header-only

lexical_cast 类型转换

Boost.Lexical_cast 提供了类似 Python 的类型转换功能。

头文件: boost/lexical_cast.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <vector>

int main() {
// 字符串转数字
std::string strNum = "123";
int num = boost::lexical_cast<int>(strNum);
std::cout << "String to int: " << num << "\n";

double d = boost::lexical_cast<double>("3.14159");
std::cout << "String to double: " << d << "\n";

// 数字转字符串
int n = 456;
std::string str = boost::lexical_cast<std::string>(n);
std::cout << "Int to string: " << str << "\n";

// 其他类型转换
bool b = boost::lexical_cast<bool>("true");
std::cout << "String to bool: " << std::boolalpha << b << "\n";

// 容器转换
std::vector<int> vec = boost::lexical_cast<std::vector<int>>("[1,2,3,4,5]");
std::cout << "Vector from string: ";
for (int v : vec) {
std::cout << v << " ";
}
std::cout << "\n";

// 自定义类型的转换
struct Point {
int x, y;
};

try {
Point p = boost::lexical_cast<Point>("(10,20)");
std::cout << "Point: (" << p.x << ", " << p.y << ")\n";
} catch (const boost::bad_lexical_cast& e) {
std::cout << "Conversion failed: " << e.what() << "\n";
}

return 0;
}

需要链接的库: header-only

noncopyable 不可复制类

Boost.Noncopyable 提供了一个简洁的方式来禁止类的拷贝构造和赋值操作。C++11 后可以使用 = delete 实现,但 noncopyable 仍然是一个清晰表达意图的方式。

头文件: boost/noncopyable.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <boost/noncopyable.hpp>
#include <iostream>

// 方式1: 继承 boost::noncopyable
class Singleton : boost::noncopyable {
public:
static Singleton& instance() {
static Singleton inst;
return inst;
}

void doSomething() {
std::cout << "Singleton working\n";
}

private:
Singleton() = default;
};

// 方式2: C++11 风格(推荐)
class ModernSingleton {
public:
static ModernSingleton& instance() {
static ModernSingleton inst;
return inst;
}

void doSomething() {
std::cout << "ModernSingleton working\n";
}

// 禁止拷贝和赋值
ModernSingleton(const ModernSingleton&) = delete;
ModernSingleton& operator=(const ModernSingleton&) = delete;

private:
ModernSingleton() = default;
};

int main() {
Singleton::instance().doSomething();
ModernSingleton::instance().doSomething();

// 以下代码会编译失败
// Singleton s1 = Singleton::instance(); // 错误:拷贝构造被禁止
// Singleton s2;
// s2 = Singleton::instance(); // 错误:赋值操作被禁止

return 0;
}

何时使用 noncopyable vs = delete

场景推荐方式
新代码(C++11+)= delete 更直观
需要同时禁止移动= delete 更灵活
代码需要兼容旧标准boost::noncopyable
表达"这个类设计上不可复制"的语义两者皆可

需要链接的库: header-only

bimap 双向映射

Boost.Bimap 提供双向映射,可以从 key 查 value,也可以从 value 查 key,两边都是"主键"。std::map/std::unordered_map 只能单向。

头文件: boost/bimap.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <boost/bimap.hpp>
#include <iostream>
#include <string>

int main() {
// 左右两边都可以作为 key 来查找
boost::bimap<std::string, int> bm;

bm.insert({"alice", 1001});
bm.insert({"bob", 1002});
bm.insert({"carol", 1003});

// 左 -> 右(name -> id)
std::cout << "alice -> " << bm.left.at("alice") << "\n";

// 右 -> 左(id -> name)
std::cout << "1003 -> " << bm.right.at(1003) << "\n";

// 遍历
for (const auto& [name, id] : bm) {
std::cout << name << " : " << id << "\n";
}

return 0;
}

还可以通过 set_of/unordered_set_of/list_of/vector_of 等修饰符控制两侧的索引类型,例如 bimap<set_of<string>, multiset_of<int>>。当两个方向都需要 O(1) 或 O(log n) 查找时,比维护两个 std::map 互相反向更安全(不会出现两边不一致)。

需要链接的库: header-only

variant2 类型安全的联合体

Boost.Variant2 是 std::variant 的改进实现,接口与 std::variant 几乎一致,但默认构造保证有值(要求第一个备选类型可默认构造)、visit 在异常路径下行为更可预测。如果项目还在用 C++17 或对 std::variant 的默认构造/异常语义不满,可以直接用。

头文件: boost/variant2.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <boost/variant2.hpp>
#include <iostream>
#include <string>

namespace v2 = boost::variant2;

int main() {
using Value = v2::variant<int, double, std::string>;

Value v = 42;
v = 3.14;
v = "hello";

// visit:对当前持有的类型做派发
v2::visit([](const auto& x) { std::cout << "value: " << x << "\n"; }, v);

// 取值(类型不对返回 nullptr)
if (auto p = v2::get_if<std::string>(&v)) {
std::cout << "string length: " << p->size() << "\n";
}

// holds_alternative 判断当前类型
std::cout << "is string? "
<< v2::holds_alternative<std::string>(v) << "\n";

return 0;
}

需要链接的库: header-only

pfr 聚合体反射

Boost.PFR 对纯聚合体(无自定义构造、无私有/保护成员、无虚函数的结构体)做编译期反射,无需宏就能遍历字段、按位置访问、比较、流式输出。C++26 才会有标准反射,PFR 是当下最轻量的替代。

头文件: boost/pfr.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <boost/pfr.hpp>
#include <iostream>
#include <string>

struct Point { int x; int y; };
struct Person { std::string name; int age; double height; };

int main() {
Point p{3, 4};

// 按位置访问
std::cout << "x=" << boost::pfr::get<0>(p)
<< " y=" << boost::pfr::get<1>(p) << "\n";

// 自动生成比较、相等
Point p2{3, 4};
std::cout << "equal? " << (p == p2) << "\n";

// 自动流式输出(无需重载 operator<<)
Person me{"alice", 30, 1.68};
std::cout << me << "\n"; // {"alice", 30, 1.68}

// 遍历所有字段
boost::pfr::for_each_field(me, [](const auto& f) {
std::cout << "field: " << f << "\n";
});

// 结构化绑定式解构(C++17 风格聚合访问)
auto [name, age, height] = me;
std::cout << name << " " << age << " " << height << "\n";

return 0;
}

最适合的场景是 POD/DTO/配置结构体——既能享受聚合体的简洁定义,又免费获得比较、哈希、IO,不用手写一堆样板。注意:只要结构体不再是聚合体(加了构造函数或私有成员),PFR 就失效。

需要链接的库: header-only

scope RAII 作用域守卫

Boost.Scope 提供 scope_exit/scope_fail/scope_success,把"退出时必做"的清理动作(释放 C 句柄、回滚事务、关闭文件描述符)封装成 RAII 对象,比手写析构类轻得多。C++23 标准库尚无等价物(std::experimental::scope_exit 一直没进标准)。

头文件: boost/scope/scope_exit.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <boost/scope/scope_exit.hpp>
#include <boost/scope/scope_fail.hpp>
#include <boost/scope/scope_success.hpp>
#include <iostream>
#include <cstdio>

int main() {
// 无论如何退出作用域都执行
auto guard = boost::scope::make_scope_exit([] {
std::cout << "cleanup: always\n";
});

// 仅在异常导致栈展开时执行(用于回滚)
auto rollback = boost::scope::make_scope_fail([] {
std::cout << "rollback on exception\n";
});

// 仅在正常返回时执行(用于提交确认)
auto commit = boost::scope::make_scope_success([] {
std::cout << "commit on success\n";
});

std::FILE* f = std::fopen("/tmp/x", "w");
auto close_guard = boost::scope::make_scope_exit([f] {
if (f) std::fclose(f);
});

// 可主动释放(之后不再执行回调)
guard.release();

return 0;
}

比手写 unique_ptr + 自定义删除器更直白地表达意图:scope_fail 就是事务回滚,scope_success 就是提交。也可以用 unique_ptr<T, Deleter> 模拟 scope_exit,但语义不如 scope_* 清晰。

需要链接的库: header-only

nowide 跨平台宽字符/UTF-8

Boost.Nowide 把 Windows 上坑爹的 wchar_t/char API(fopenargvmainstd::cout 等)统一封装成 UTF-8 接口,在 POSIX 上直接透传。这样同一段代码在 Windows 和 Linux 下都能正确处理非 ASCII 路径和命令行参数,不必到处写 #ifdef _WIN32

头文件: boost/nowide/iostream.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <boost/nowide/args.hpp>
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/fstream.hpp>
#include <string>

int main(int argc, char** argv) {
// 把 argv 转成 UTF-8(Windows 下从宽字符还原)
boost::nowide::args a(argc, argv);

for (int i = 0; i < argc; ++i) {
boost::nowide::cout << "argv[" << i << "] = " << argv[i] << "\n";
}

// 直接用 UTF-8 路径打开文件,跨平台
std::string path = "/tmp/中文.txt";
boost::nowide::ofstream out(path);
out << "hello 你好\n";

return 0;
}

需要链接的库: header-only(部分平台实现依赖系统库)

mp11 编译期元编程

Boost.Mp11 是一个极简的元编程库,把类型列表当 mp_list<T...> 操作,提供 mp_size/mp_at/mp_for_each/mp_transform 等一套函数式接口。比手写可变参数模板递归直观得多,编译速度也快。在需要遍历变参包、做类型过滤/转换时非常顺手。

头文件: boost/mp11.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <boost/mp11.hpp>
#include <iostream>
#include <type_traits>

namespace mp = boost::mp11;

int main() {
using Types = mp::mp_list<int, double, char, float, long>;

// 类型列表长度
static_assert(mp::mp_size<Types>::value == 5);

// 取第 2 个类型
static_assert(std::is_same_v<mp::mp_at_c<Types, 2>, char>);

// 对每个类型执行(编译期展开循环)
mp::mp_for_each<Types>([](auto x) {
using T = decltype(x);
std::cout << "sizeof = " << sizeof(T) << "\n";
});

// 类型变换:把每个类型包成 const
using ConstTypes = mp::mp_transform<std::add_const_t, Types>;
static_assert(std::is_same_v<mp::mp_at_c<ConstTypes, 0>, const int>);

// 过滤:只保留小于 8 字节的类型
using Small = mp::mp_copy_if<Types, [](auto T) {
return sizeof(typename decltype(T)::type) < 8;
}>;
static_assert(mp::mp_size<Small>::value == 3);

return 0;
}

需要链接的库: header-only

总结

功能需要链接的动态库
timer计时器libboost_timer, libboost_chrono
algorithm/string字符串分割、处理header-only
circular_buffer环形缓冲区header-only
heap优先队列header-only
lockfree无锁数据结构header-only
string_algo字符串算法header-only
tokenizer字符串分词器header-only
pool内存池header-only
lexical_cast类型转换header-only
noncopyable不可复制类header-only
bimap双向映射header-only
variant2类型安全的联合体header-only
pfr聚合体反射header-only
scopeRAII 作用域守卫header-only
nowide跨平台 UTF-8/宽字符header-only
mp11编译期元编程header-only

注意: header-only 的库直接包含头文件即可使用。但某些情况下可能仍需要链接 libboost_system 等基础库。timer 需要链接 libboost_timerlibboost_chrono