Macro Metaprogramming
GMP's macro layer is a C++11 preprocessor toolkit for generating tokens before the compiler parses the program. It handles the unglamorous but necessary parts of macro programming: argument counting, tuple-like macro data, conditional expansion, repetition, overload dispatch, token concatenation, and namespace generation.
Use it through:
#include <gmp/macro/macro.hpp>
// or
#include <gmp/gmp.hpp>
The Preprocessor Layer
The module is organized around a few reusable building blocks:
- Conditional expansion with
GMP_BOOL,GMP_NOT,GMP_AND,GMP_OR,GMP_IF, andGMP_IF_THEN_ELSE - Token utilities such as
GMP_STRINGIFY,GMP_CONCAT,GMP_CONCATS, andGMP_EXPAND - Variadic argument tools such as
GMP_SIZE_OF_VAARGS,GMP_GET_N,GMP_GET_FIRST_N, andGMP_IS_EMPTY - Tuple helpers such as
GMP_TUPLE_SIZE,GMP_GET_TUPLE,GMP_TUPLE_APPEND,GMP_TUPLE_TAKE, andGMP_TUPLE_SKIP - Generation helpers such as
GMP_REPEAT,GMP_FOR_EACH,GMP_OVERLOAD_INVOKE,GMP_RANGE, andGMP_GENERATE_NAMESPACES_BEGIN
When It Helps
Templates are excellent once C++ syntax exists, but they cannot create new tokens before parsing. Macro metaprogramming is still useful when a library needs to generate declarations, repeat similar code, build identifiers, select a generated macro overload, or support older standards where newer template techniques are unavailable.
GMP gives those patterns stable names. Instead of writing another private recursive macro system, you can use the same primitives for repeated fields, generated overloads, dispatch tables, or namespace wrappers.
Common Patterns
Use conditionals when the generated code depends on preprocessor-time state:
#include <gmp/gmp.hpp>
GMP_IF(1, int enabled;)
GMP_IF_THEN_ELSE(0, int yes;, int no;)
Treat variadic arguments and tuple-like macro values as data:
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)
Generate repeated declarations from a compact list:
#define DECLARE_FIELD(name) int name;
struct record {
GMP_FOR_EACH(DECLARE_FIELD, id, count, flags)
};
#undef DECLARE_FIELD
Build macro names from arguments:
#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
Generate nested namespace blocks:
GMP_GENERATE_NAMESPACES_BEGIN(my_library, detail)
struct generated_type {};
GMP_GENERATE_NAMESPACES_END(my_library, detail)