// [Overview](#Overview) / [Examples](#Examples) / [API](#API) / [FAQ](#FAQ) / [Resources](#Resources) ## MP: ~~Template~~ Meta-Programming library [![MIT Licence](http://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/license/mit) [![Version](https://img.shields.io/github/v/release/qlibs/mp)](https://github.com/qlibs/mp/releases) [![Build](https://img.shields.io/badge/build-green.svg)](https://godbolt.org/z/6asb6K4EK) [![Try it online](https://img.shields.io/badge/try%20it-online-blue.svg)](https://godbolt.org/z/3TqPx5WEG) > https://en.wikipedia.org/wiki/Template_metaprogramming ### Features - Single header (https://raw.githubusercontent.com/qlibs/mp/main/mp) / C++20 module (https://raw.githubusercontent.com/qlibs/mp/main/mp.cppm) - Minimal [API](#api) and learning curve (supports STL, ranges, ...) - Supports debugging (meta-functions can be executed and debugged at run-time - see [examples](#examples)) - Supports reflection (requires https://github.com/qlibs/reflect - see [examples](#examples)) - Verifies itself upon include (can be disabled with `-DNTEST` - see [FAQ](#faq)) - Optimized compilation-times (see [benchmarks](https://qlibs.github.io/mp)) ### Requirements - C++20 ([clang++13+, g++11+, msvc-19.34+](https://en.cppreference.com/w/cpp/compiler_support)) ### Overview > API (https://godbolt.org/z/zTdYGvKKW) ```cpp // mp::meta static_assert(mp::meta == mp::meta); static_assert(mp::meta != mp::meta); static_assert(typeid(mp::meta) == typeid(mp::meta)); // mp::type_of constexpr mp::info meta = mp::meta; mp::type_of i{}; // same as int i{}; mp::type_of> b = true; // same as bool b = true; // mp::apply template struct type_list{ }; static_assert(std::is_same_v, mp::apply_t>); // mp::invoke static_assert(not mp::invoke(meta)); static_assert(std::is_same_v(meta)>>); int main() { // mp::for_each constexpr auto v = mp::vector{meta}; mp::for_each([&]{ /* ... */ }); } // and more (see API)... ``` ### Examples > Hello World (https://godbolt.org/z/69jGzqPs1) ```cpp template using at_c = mp::type_of...}[N]>; static_assert(std::is_same_v>); static_assert(std::is_same_v>); static_assert(std::is_same_v>); ``` > Algorithms (https://godbolt.org/z/GvzjvdPq8) ```cpp template struct example { mp::apply_t...} | std::views::drop(1) | std::views::reverse | std::views::filter([](auto m) { return mp::invoke(m); }) | std::views::transform([](auto m) { return mp::invoke(m); }) | std::views::take(2) | std::ranges::to>() > v; }; static_assert( typeid(std::variant) == typeid(example::v) ); ``` > Reflection - https://github.com/qlibs/reflect (https://godbolt.org/z/qb37G79Ya) ```cpp struct foo { int a; bool b; float c; }; constexpr foo f{.a = 42, .b = true, .c = 3.2f}; constexpr mp::vector v = members(f) | std::views::filter([&](auto meta) { return member_name(meta, f) != "b"; }) ; static_assert(std::tuple{42, 3.2f} == to(f)); ``` > Run-time testing/debugging (https://godbolt.org/z/vTfGGToa4) ```cpp constexpr auto reverse(std::ranges::range auto v) { std::reverse(v.begin(), v.end()); return v; } int main() { static_assert( std::array{mp::meta, mp::meta, mp::meta} == reverse(std::array{mp::meta, mp::meta, mp::meta}) ); assert(( std::array{mp::meta, mp::meta, mp::meta} == reverse(std::array{mp::meta, mp::meta, mp::meta}) )); } ``` ### API ```cpp namespace mp::inline v2_0_11 { /** * Meta info type */ enum class info : size_t { }; /** * Creates meta type * * @code * static_assert(meta == meta); * static_assert(meta != meta); * @endcode */ template inline constexpr info meta = /* unspecified */; /** * Returns underlying type from meta type * * @code * static_assert(typeid(type_of>) == typeid(void)); * @endcode */ template using type_of = /* unspecified */; /** * Applies invocable `[] { return vector{...}; }` to * `T...>` * * @code * static_assert(typeid(variant) == * typeid(apply([] { return vector{meta}; }))); * @endcode */ template class T> [[nodiscard]] constexpr auto apply(concepts::invocable auto expr); /** * Applies range to `T...>` * * @code * static_assert(typeid(variant) == * typeid(apply}>)); * @endcode */ template class T, concepts::range auto range> inline constexpr auto apply_v = decltype(apply); /** * Applies range to `T...>` * * @code * static_assert(typeid(variant) == * typeid(apply_t}; }>)); * @endcode */ template class T, concepts::range auto range> using apply_t = decltype(apply_v); /** * Invokes function with compile-time info based on meta-info * * @code * static_assert(invoke( * [] { return std::is_const_v>; * }, meta)); * @endcode */ [[nodiscard]] constexpr auto invoke(auto&& fn, info meta); /** * Invokes type_trait with meta-info * * @code * static_assert(not invoke(meta)); * static_assert(invoke(meta)); * @endcode */ template class T, class... Ts> [[nodiscard]] constexpr auto invoke(info meta); /** * unrolls fn N times # optionally passes index I to fn * @code * mp::unroll<3>([]{ std::print("mp"); }); // prints 'mpmpmp' * mp::unroll<3>([]{ std::print("{}", I); }); // prints '012' * @endcode */ template inline constexpr auto unroll(auto&& fn); /** * Iterates over all elements of a range * * @code * constexpr vector v{meta}; * for_each([] { * static_assert(typeid(int) == typeid(type_of)); * }); * @endcode */ template inline constexpr auto for_each(auto&& fn); } // namesapce mp ``` ### FAQ > - What does it mean that `mp` tests itself upon include? > > `mp` runs all tests (via static_asserts) upon include. If the include compiled it means all tests are passing and the library works correctly on given compiler, enviornment. > > - How to disable running tests at compile-time? > > When `-DNTEST` is defined static_asserts tests wont be executed upon include. > Note: Use with caution as disabling tests means that there are no gurantees upon include that given compiler/env combination works as expected. > > - How does it work? > > Template-less Metaprogramming > - Video - https://www.youtube.com/watch?v=yriNqhv-oM0 > - Slides - https://kris-jusiak.github.io/talks/cppcon-2024 > - Source code - https://godbolt.org/z/Kf9rovaqE (~100 LOC, C++17, gcc, clang, msvc, no dependencies) > > - How `mp` compares to Reflection for C++26 (https://wg21.link/P2996)? > > `mp` meta-programming model is very simpilar to P2996 and its based on type erased info object and meta-functions. `mp` also supports all C++ standard library and since verion 2.0.0+ `mp` type names have been adopted to closer reflect the reflection proposal. > > | mp (C++20) | P2996 (C++26*) | > | - | - | > | `meta` | `^^T` | > | `using info = decltype(meta)` | `using info = decltype(^^::)` | > | `type_of` | `typename [: T :]` | > | `for_each` | `template for` (https://wg21.link/p1306) | > | `apply_t` | `substitute` | > | `invoke` | `reflect_invoke` | > | `invoke` | `test_trait` | > | `invoke` | `extract` | > > - Similar projects? > > [boost.mp11](https://github.com/boostorg/mp11), [boost.hana](https://github.com/boostorg/hana), [boost.fusion](https://github.com/boostorg/fusion), [boost.mpl](https://github.com/boostorg/mpl) ### Resources > - https://wg21.link/P2996 (Reflection for C++26) > - https://github.com/seanbaxter/circle (Circle-lang) > - https://zig.guide/language-basics/comptime (Zig-comptime) ### License > - [MIT](LICENSE)