跳到主要内容

宏元编程

GMP 的宏层是一个 C++11 预处理器工具箱,用于在编译器解析程序之前生成 token。它处理宏编程中常见但繁琐的部分:参数计数、tuple 风格宏数据、条件展开、重复生成、重载分发、token 拼接和命名空间生成。

入口头文件:

#include <gmp/macro/macro.hpp>
// 或
#include <gmp/gmp.hpp>

预处理器工具层

这个模块围绕几类可复用能力组织:

  • 条件展开:GMP_BOOLGMP_NOTGMP_ANDGMP_ORGMP_IFGMP_IF_THEN_ELSE
  • token 工具:GMP_STRINGIFYGMP_CONCATGMP_CONCATSGMP_EXPAND
  • 可变参数工具:GMP_SIZE_OF_VAARGSGMP_GET_NGMP_GET_FIRST_NGMP_IS_EMPTY
  • tuple 工具:GMP_TUPLE_SIZEGMP_GET_TUPLEGMP_TUPLE_APPENDGMP_TUPLE_TAKEGMP_TUPLE_SKIP
  • 生成工具:GMP_REPEATGMP_FOR_EACHGMP_OVERLOAD_INVOKEGMP_RANGEGMP_GENERATE_NAMESPACES_BEGIN

适合使用的场景

模板在 C++ 语法已经存在之后很强,但它不能在解析前创造新的 token。宏元编程仍然适合生成声明、重复相似代码、构造标识符、选择生成的宏重载,或者在较旧标准下完成模板不方便表达的任务。

GMP 为这些模式提供稳定的命名工具。你不需要在每个项目里重新写一套递归宏系统,而是可以用同一组基础设施生成字段、重载入口、分发代码或命名空间包装。

常见用法

条件展开:

#include <gmp/gmp.hpp>

GMP_IF(1, int enabled;)
GMP_IF_THEN_ELSE(0, int yes;, int no;)

把可变参数和 tuple 风格宏值当作数据处理:

GMP_SIZE_OF_VAARGS(a, b, c) // 3
GMP_GET_N(1, a, b, c) // b

GMP_TUPLE_SIZE((x, y, z)) // 3
GMP_GET_TUPLE(1, (x, y, z)) // y
GMP_TUPLE_APPEND((x, y), z) // (x, y, z)
GMP_TUPLE_TAKE(2, (x, y, z, w)) // (x, y)

从紧凑列表生成重复声明:

#define DECLARE_FIELD(name) int name;

struct record {
GMP_FOR_EACH(DECLARE_FIELD, id, count, flags)
};

#undef DECLARE_FIELD

根据参数构造宏名:

#define HANDLER_read read_handler
#define HANDLER_read_write read_write_handler

GMP_OVERLOAD_INVOKE(HANDLER, read) // HANDLER_read
GMP_OVERLOAD_INVOKE(HANDLER, read, write) // HANDLER_read_write