- Overview
- Compiler Support
- Install
- Macro metaprogramming
- Reflection metaprogramming
- Compile-time tests
- Acknowledgments
GMP is a header-only C++ metaprogramming library for compile-time programming and code generation. It provides two complementary parts:
- Macro metaprogramming: A rich set of preprocessor utilities for boolean logic, arithmetic, tuple operations, loops, and code generation. This part is available in C++11.
- Reflection metaprogramming: A set of compile-time utilities for fixed strings, type names, enum names, and aggregate member names. This part was introduced in v0.2.0 and requires C++20.
Key Features
- Header-only design: Zero compilation required, just include and use
- Two-tier language support:
- Macro metaprogramming features require C++11
- Reflection metaprogramming features require C++20
- Cross-platform: Compatible with GCC, Clang, and MSVC
- Zero dependencies: Pure standard C++, with no external dependencies
- Compile-time focused: Designed for compile-time evaluation and code generation
- Comprehensive utilities: Covers both macro-based and modern compile-time metaprogramming workflows
GMP provides two feature sets with different compiler requirements:
Macro Metaprogramming
The macro metaprogramming utilities should also work correctly with C++98 compilers, although they are primarily documented and tested in C++11 and later.
Reflection Metaprogramming
The reflection metaprogramming utilities require C++20 and the following compiler versions or newer:
| Compiler | Minimum Version |
|---|---|
| MSVC | 19.37+ |
| GCC | 11.1+ |
| Clang | 18.1.0+ |
Try online quickly:
Compiler Explorer: https://godbolt.org/z/W156818n5
Header-only version
Copy the include folder to your build tree and use a C++11 compiler.
CMake integration
Install system-wide and use CMake's find_package:
$ git clone https://github.com/lkimuk/gmp.git
$ cd gmp
$ cmake -B ./build
$ cmake --build ./build
$ cmake --install ./build # sudo on Linux/macOSfind_package(gmp 0.1.0 REQUIRED)
target_link_libraries(your_target PRIVATE gmp::gmp)- Boolean operations:
GMP_BOOL,GMP_NOT,GMP_AND,GMP_OR,GMP_XOR,GMP_IMPLIES - Arithmetic macros:
GMP_INC,GMP_DEC,GMP_ADD,GMP_SUB - Comparison macros:
GMP_EQUAL_INT,GMP_GREATER_INT,GMP_GREATER_EQUAL_INT,GMP_LESS_INT,GMP_LESS_EQUAL_INT,GMP_EQUAL_INT_INDEPENDENT - Conditional macros:
GMP_IF,GMP_IF_THEN_ELSE - Stringification:
GMP_STRINGIFY,GMP_CONCAT,GMP_CONCATS - Variadic handling:
GMP_SIZE_OF_VAARGS,GMP_GET_N,GMP_IS_EMPTY,GMP_GET_FIRST_N - Algorithms:
GMP_MAX,GMP_MIN,GMP_MINMAX,GMP_MAXMIN,GMP_SWAP - Remove trailing comma:
GMP_REMOVE_TRAILING_COMMA - Identifies:
GMP_IDENTIFIERS
- Size & Access:
GMP_TUPLE_SIZE,GMP_GET_TUPLE,GMP_IS_TUPLE - Modification:
GMP_TUPLE_APPEND,GMP_TUPLE_PREPEND,GMP_TUPLE_CONCAT - Slicing:
GMP_TUPLE_SKIP,GMP_TUPLE_TAKE
- Loop macros:
GMP_REPEAT,GMP_WHILE,GMP_FOR_EACH,GMP_FOR_EACH_INDEPENDENT - Overload functions matching:
GMP_OVERLOAD_INVOKE - Expand control:
GMP_EXPAND,GMP_EVAL,GMP_DEFER - Index sequences:
GMP_MAKE_INDEX_SEQUENCE,GMP_RANGE - Namespace generation:
GMP_GENERATE_NAMESPACES_BEGIN,GMP_GENERATE_NAMESPACES_END
#include <gmp/gmp.hpp>
// Boolean and logical operations
static_assert(GMP_BOOL(42) == 1, "Non-zero values are true");
static_assert(GMP_NOT(0) == 1, "NOT false is true");
static_assert(GMP_AND(1, 1) == 1, "Logical AND");
static_assert(GMP_OR(0, 1) == 1, "Logical OR");
static_assert(GMP_XOR(1, 0) == 1, "Logical XOR");
// Arithmetic operations
static_assert(GMP_INC(5) == 6, "Increment");
static_assert(GMP_DEC(8) == 7, "Decrement");
static_assert(GMP_ADD(2, 3) == 5, "Addition");
static_assert(GMP_SUB(10, 4) == 6, "Subtraction");
static_assert(GMP_SUB(3, 5) == -2, "Negative subtraction");
// Comparison operations
static_assert(GMP_EQUAL_INT(5, 5) == 1, "Equality check");
static_assert(GMP_GREATER_INT(7, 3) == 1, "Greater than");
static_assert(GMP_LESS_INT(2, 9) == 1, "Less than");
static_assert(GMP_MAX(3, 7) == 7, "Maximum value");
static_assert(GMP_MIN(10, 2) == 2, "Minimum value");
// Conditional operations
GMP_IF(1, expr) // expands to: expr
GMP_IF(0, expr) // expands to:
GMP_IF_THEN_ELSE(1, expr1, expr2) // expands to: expr1
GMP_IF_THEN_ELSE(0, expr1, expr2) // expands to: expr2
// Variadic operations
GMP_SIZE_OF_VAARGS() // expands to: 0
GMP_SIZE_OF_VAARGS(1) // expands to: 1
GMP_SIZE_OF_VAARGS('a', 'b') // expands to: 2
GMP_SIZE_OF_VAARGS('a', 'b', 'c') // expands to: 3
GMP_SIZE_OF_VAARGS('a', 'b', 1, 2) // expands to: 4
GMP_SIZE_OF_VAARGS('a', 'b', 1, 2, 3) // expands to: 5
GMP_SIZE_OF_VAARGS('a', 'b', 1, 2, 3, 4) // expands to: 6
GMP_SIZE_OF_VAARGS('a', 'b', 1, 2, 3, 4, 5) // expands to: 7
GMP_IS_EMPTY() // expands to: 1
GMP_IS_EMPTY(1) // expands to: 0
GMP_IS_EMPTY(1, 2) // expands to: 0
GMP_GET_N(0, a, b, c) // expands to: a
GMP_GET_N(1, a, b, c) // expands to: b
GMP_GET_N(2, a, b, c) // expands to: c
// Algorithms
GMP_MINMAX(7, 3) // expands to: (3, 7)
GMP_MINMAX(2, 10) // expands to: (2, 10)
GMP_MINMAX(5, 5) // expands to: (5, 5)
GMP_MAXMIN(7, 3) // expands to: (7, 3)
GMP_MAXMIN(2, 10) // expands to: (10, 2)
GMP_MAXMIN(5, 5) // expands to: (5, 5)
GMP_SWAP(x, y) // expands to: y, xGMP_TUPLE_SIZE(()); // expands to: 0
GMP_TUPLE_SIZE((a, b, c, d, e)) // expands to: 5
GMP_TUPLE_TAKE(2, (a, b, c, d, e)) // expands to: (a, b)
GMP_TUPLE_TAKE(0, (a, b, c, d, e)) // expands to: ()
GMP_TUPLE_TAKE(5, (a, b, c, d, e)) // expands to: (a, b, c, d, e)
GMP_TUPLE_TAKE(10, (a, b, c, d, e)) // expands to: (a, b, c, d, e)
GMP_TUPLE_SKIP(2, (a, b, c, d, e)) // expands to: (c, d, e)
GMP_TUPLE_SKIP(0, (a, b, c, d, e)) // expands to: (a, b, c, d, e)
GMP_TUPLE_SKIP(5, (a, b, c, d, e)) // expands to: ()
GMP_TUPLE_SKIP(10, (a, b, c, d, e)) // expands to: ()
GMP_TUPLE_APPEND((a, b, c, d, e), f) // expands to: (a, b, c, d, e, f)
GMP_TUPLE_APPEND((), f) // expands to: (f)
GMP_TUPLE_PREPEND((b, c, d), a) // expands to: (a, b, c, d)
GMP_TUPLE_PREPEND((), x) // expands to: (x)
GMP_TUPLE_PREPEND(GMP_TUPLE_PREPEND((c, d), b), a) // expands to: (a, b, c, d)
GMP_TUPLE_CONCAT((), (a, b, c)) // expands to: (a, b, c)
GMP_TUPLE_CONCAT((a, b, c), (a, b, c)) // expands to: (a, b, c, a, b, c)
GMP_TUPLE_CONCAT((a, b, c), ()) // expands to: (a, b, c)
GMP_TUPLE_CONCAT((), ()) // expands to: ()
GMP_GET_TUPLE(0, (int, float, char)) // expands to: int
GMP_GET_TUPLE(1, (42, "hello", 3.14)) // expands to: "hello"#define Bar(arg1, arg2) bar(arg1, arg2);
// Expands to: bar(1, "arg2"); bar(1, "arg2"); bar(1, "arg2"); ... (100 times)
GMP_REPEAT(Bar, 100, 1, "arg2")
#define PRINT(x) std::cout << x << " ";
// Expands to: std::cout << 1 << " "; std::cout << 2 << " "; std::cout << 3 << " ";
GMP_FOR_EACH(PRINT, 1, 2, 3)
#define OVERLOAD_FUNCTION_0 "OVERLOAD_FUNCTION_0"
#define OVERLOAD_FUNCTION_1 "OVERLOAD_FUNCTION_1"
#define OVERLOAD_FUNCTION_X_Y "OVERLOAD_FUNCTION_X_Y"
GMP_OVERLOAD_INVOKE(OVERLOAD_FUNCTION, 0) // expands to: "OVERLOAD_FUNCTION_0"
GMP_OVERLOAD_INVOKE(OVERLOAD_FUNCTION, 1) // expands to: "OVERLOAD_FUNCTION_1"
GMP_OVERLOAD_INVOKE(OVERLOAD_FUNCTION, X, Y) // expands to: "OVERLOAD_FUNCTION_X_Y"
GMP_MAKE_INDEX_SEQUENCE(0) // expands to:
GMP_MAKE_INDEX_SEQUENCE(5) // expands to: 0, 1, 2, 3, 4
GMP_MAKE_INDEX_SEQUENCE(42) // expands to: 0, 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
GMP_RANGE(0, 0) // expands to:
GMP_RANGE(0, 5) // expands to: 0 , 1 , 2 , 3 , 4
GMP_RANGE(5, 10) // expands to: 5 , 6 , 7 , 8 , 9
GMP_STRINGIFY(GMP_CONCATS(abc, 123, def, 456)) // expands to: "abc123def456"
#define MYLIB_NAMESPACE_BEGIN GMP_GENERATE_NAMESPACES_BEGIN(mylib, parser)
#define MYLIB_NAMESPACE_END GMP_GENERATE_NAMESPACES_END(mylib, parser)
/// expands to:
/// namespace mylib { namespace parser {
/// } }
MYLIB_NAMESPACE_BEGIN
MYLIB_NAMESPACE_ENDCompile-time Fixed String
fixed_string: A compile-time string type whose content can be manipulatedoperator+(fixed_string, fixed_string): Concatenates twofixed_stringvaluesremove_all<Values...>(constant_arg_t<fixed_string>): Removes all occurrences ofValues...from afixed_string
Utilities
constant_arg_t<V>: Statically enforces the type of an NTTP compile-time argumentconstant_arg<V>: Statically enforces thatVis a compile-time valueany: A type implicitly convertible to any typeas_value<T>(): Defines a compile-time value of typeT
Meta Functions
type_name<T>(): Returns the string representation ofTat compile timeenum_count<E>(): Returns the number of enumerators in an enumeration type at compile timeenum_name<V>(): Returns the name of an enumerator at compile timeenum_names<E>(): Returns all enumerator names of an enumeration type at compile timemember_count<T>(): Returns the number of members in an aggregate type at compile timemember_name<I, T>(): Returns the name of theI-th member of a type at compile timemember_names<T>(): Returns the names of all members of a type at compile time
Reflection Metaprogramming
#include <gmp/gmp.hpp>
struct S {
double b;
std::string str;
};
enum class Color { Red, Green, Blue, Yellow };
enum class Empty {};
int main() {
constexpr auto int_name = gmp::type_name<int>();
std::cout << "int: " << int_name << "\n";
std::cout << "float: " << gmp::type_name<float>().to_string_view() << "\n";
std::cout << "std::vector<std::string>: " << gmp::type_name<std::vector<std::string>>() << "\n";
std::cout << gmp::member_count<S>() << "\n";
std::cout << gmp::member_name<0, S>() << "\n";
std::cout << gmp::member_name<1, S>() << "\n";
std::cout << "------------------------\n";
for (const auto& e : gmp::enum_names<enum_test::Color>()) {
std::cout << e << ", ";
}
std::cout << "\n------------------------\n";
for (const auto& e : gmp::member_names<S>()) {
std::cout << e << ", ";
}
std::cout << "\n------------------------\n";
}Outputs:
Clang
int: int
float: float
std::vector<std::string>: std::vector<std::basic_string<char>>
2
b
str
------------------------
Red, Green, Blue, Yellow,
------------------------
b, str,
------------------------
GCC:
int: int
float: float
std::vector<std::string>: std::vector<std::__cxx11::basic_string<char> >
2
b
str
------------------------
Red, Green, Blue, Yellow,
------------------------
b, str,
------------------------
MSVC:
int: int
float: float
std::vector<std::string>: std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >
2
b
str
------------------------
Red, Green, Blue, Yellow,
------------------------
b, str,
------------------------
The library includes comprehensive compile-time tests using static_assert:
# Build tests
# The tests are compile-time only - successful build means all tests passed.
cmake -B ./build -DBUILD_TESTS=ON
cmake --build ./buildInspired by Boost.Preprocessor and other metaprogramming libraries.
GMP is licensed under the MIT license, see LICENSE for more information.