├── .github ├── LICENSE └── README.md ├── mp └── mp.cppm /.github/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2025 Kris Jusiak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | ../mp -------------------------------------------------------------------------------- /mp: -------------------------------------------------------------------------------- 1 | // 26 | [Overview](#Overview) / [Examples](#Examples) / [API](#API) / [FAQ](#FAQ) / [Resources](#Resources) 27 | 28 | ## MP: ~~Template~~ Meta-Programming library 29 | 30 | [![MIT Licence](http://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/license/mit) 31 | [![Version](https://img.shields.io/github/v/release/qlibs/mp)](https://github.com/qlibs/mp/releases) 32 | [![Build](https://img.shields.io/badge/build-green.svg)](https://godbolt.org/z/6asb6K4EK) 33 | [![Try it online](https://img.shields.io/badge/try%20it-online-blue.svg)](https://godbolt.org/z/3TqPx5WEG) 34 | 35 | > https://en.wikipedia.org/wiki/Template_metaprogramming 36 | 37 | ### Features 38 | 39 | - Single header (https://raw.githubusercontent.com/qlibs/mp/main/mp) / C++20 module (https://raw.githubusercontent.com/qlibs/mp/main/mp.cppm) 40 | - Minimal [API](#api) and learning curve (supports STL, ranges, ...) 41 | - Supports debugging (meta-functions can be executed and debugged at run-time - see [examples](#examples)) 42 | - Supports reflection (requires https://github.com/qlibs/reflect - see [examples](#examples)) 43 | - Verifies itself upon include (can be disabled with `-DNTEST` - see [FAQ](#faq)) 44 | - Optimized compilation-times (see [benchmarks](https://qlibs.github.io/mp)) 45 | 46 | ### Requirements 47 | 48 | - C++20 ([clang++13+, g++11+, msvc-19.34+](https://en.cppreference.com/w/cpp/compiler_support)) 49 | 50 | ### Overview 51 | 52 | > API (https://godbolt.org/z/zTdYGvKKW) 53 | 54 | ```cpp 55 | // mp::meta 56 | static_assert(mp::meta == mp::meta); 57 | static_assert(mp::meta != mp::meta); 58 | static_assert(typeid(mp::meta) == typeid(mp::meta)); 59 | 60 | // mp::type_of 61 | constexpr mp::info meta = mp::meta; 62 | mp::type_of i{}; // same as int i{}; 63 | mp::type_of> b = true; // same as bool b = true; 64 | 65 | // mp::apply 66 | template struct type_list{ }; 67 | static_assert(std::is_same_v, mp::apply_t>); 68 | 69 | // mp::invoke 70 | static_assert(not mp::invoke(meta)); 71 | static_assert(std::is_same_v(meta)>>); 72 | 73 | int main() { 74 | // mp::for_each 75 | constexpr auto v = mp::vector{meta}; 76 | mp::for_each([&]{ /* ... */ }); 77 | } 78 | 79 | // and more (see API)... 80 | ``` 81 | 82 | ### Examples 83 | 84 | > Hello World (https://godbolt.org/z/69jGzqPs1) 85 | 86 | ```cpp 87 | template 88 | using at_c = mp::type_of...}[N]>; 89 | 90 | static_assert(std::is_same_v>); 91 | static_assert(std::is_same_v>); 92 | static_assert(std::is_same_v>); 93 | ``` 94 | 95 | > Algorithms (https://godbolt.org/z/GvzjvdPq8) 96 | 97 | ```cpp 98 | template 99 | struct example { 100 | mp::apply_t...} 102 | | std::views::drop(1) 103 | | std::views::reverse 104 | | std::views::filter([](auto m) { return mp::invoke(m); }) 105 | | std::views::transform([](auto m) { return mp::invoke(m); }) 106 | | std::views::take(2) 107 | | std::ranges::to>() 108 | > v; 109 | }; 110 | 111 | static_assert( 112 | typeid(std::variant) 113 | == 114 | typeid(example::v) 115 | ); 116 | ``` 117 | 118 | > Reflection - https://github.com/qlibs/reflect (https://godbolt.org/z/qb37G79Ya) 119 | 120 | ```cpp 121 | struct foo { 122 | int a; 123 | bool b; 124 | float c; 125 | }; 126 | 127 | constexpr foo f{.a = 42, .b = true, .c = 3.2f}; 128 | 129 | constexpr mp::vector v = 130 | members(f) 131 | | std::views::filter([&](auto meta) { return member_name(meta, f) != "b"; }) 132 | ; 133 | 134 | static_assert(std::tuple{42, 3.2f} == to(f)); 135 | ``` 136 | 137 | > Run-time testing/debugging (https://godbolt.org/z/vTfGGToa4) 138 | 139 | ```cpp 140 | constexpr auto reverse(std::ranges::range auto v) { 141 | std::reverse(v.begin(), v.end()); 142 | return v; 143 | } 144 | 145 | int main() { 146 | static_assert( 147 | std::array{mp::meta, mp::meta, mp::meta} 148 | == 149 | reverse(std::array{mp::meta, mp::meta, mp::meta}) 150 | ); 151 | 152 | assert(( 153 | std::array{mp::meta, mp::meta, mp::meta} 154 | == 155 | reverse(std::array{mp::meta, mp::meta, mp::meta}) 156 | )); 157 | } 158 | ``` 159 | 160 | ### API 161 | 162 | ```cpp 163 | namespace mp::inline v2_0_11 { 164 | /** 165 | * Meta info type 166 | */ 167 | enum class info : size_t { }; 168 | 169 | /** 170 | * Creates meta type 171 | * 172 | * @code 173 | * static_assert(meta == meta); 174 | * static_assert(meta != meta); 175 | * @endcode 176 | */ 177 | template inline constexpr info meta = /* unspecified */; 178 | 179 | /** 180 | * Returns underlying type from meta type 181 | * 182 | * @code 183 | * static_assert(typeid(type_of>) == typeid(void)); 184 | * @endcode 185 | */ 186 | template using type_of = /* unspecified */; 187 | 188 | /** 189 | * Applies invocable `[] { return vector{...}; }` to 190 | * `T...>` 191 | * 192 | * @code 193 | * static_assert(typeid(variant) == 194 | * typeid(apply([] { return vector{meta}; }))); 195 | * @endcode 196 | */ 197 | template class T> 198 | [[nodiscard]] constexpr auto apply(concepts::invocable auto expr); 199 | 200 | /** 201 | * Applies range to `T...>` 202 | * 203 | * @code 204 | * static_assert(typeid(variant) == 205 | * typeid(apply}>)); 206 | * @endcode 207 | */ 208 | template class T, concepts::range auto range> 209 | inline constexpr auto apply_v = decltype(apply); 210 | 211 | /** 212 | * Applies range to `T...>` 213 | * 214 | * @code 215 | * static_assert(typeid(variant) == 216 | * typeid(apply_t}; }>)); 217 | * @endcode 218 | */ 219 | template class T, concepts::range auto range> 220 | using apply_t = decltype(apply_v); 221 | 222 | /** 223 | * Invokes function with compile-time info based on meta-info 224 | * 225 | * @code 226 | * static_assert(invoke( 227 | * [] { return std::is_const_v>; 228 | * }, meta)); 229 | * @endcode 230 | */ 231 | [[nodiscard]] constexpr auto invoke(auto&& fn, info meta); 232 | 233 | /** 234 | * Invokes type_trait with meta-info 235 | * 236 | * @code 237 | * static_assert(not invoke(meta)); 238 | * static_assert(invoke(meta)); 239 | * @endcode 240 | */ 241 | template class T, class... Ts> 242 | [[nodiscard]] constexpr auto invoke(info meta); 243 | 244 | /** 245 | * unrolls fn N times # optionally passes index I to fn 246 | * @code 247 | * mp::unroll<3>([]{ std::print("mp"); }); // prints 'mpmpmp' 248 | * mp::unroll<3>([]{ std::print("{}", I); }); // prints '012' 249 | * @endcode 250 | */ 251 | template 252 | inline constexpr auto unroll(auto&& fn); 253 | 254 | /** 255 | * Iterates over all elements of a range 256 | * 257 | * @code 258 | * constexpr vector v{meta}; 259 | * for_each([] { 260 | * static_assert(typeid(int) == typeid(type_of)); 261 | * }); 262 | * @endcode 263 | */ 264 | template 265 | inline constexpr auto for_each(auto&& fn); 266 | } // namesapce mp 267 | ``` 268 | 269 | ### FAQ 270 | 271 | > - What does it mean that `mp` tests itself upon include? 272 | > 273 | > `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. 274 | > 275 | > - How to disable running tests at compile-time? 276 | > 277 | > When `-DNTEST` is defined static_asserts tests wont be executed upon include. 278 | > Note: Use with caution as disabling tests means that there are no gurantees upon include that given compiler/env combination works as expected. 279 | > 280 | > - How does it work? 281 | > 282 | > Template-less Metaprogramming 283 | > - Video - https://www.youtube.com/watch?v=yriNqhv-oM0 284 | > - Slides - https://kris-jusiak.github.io/talks/cppcon-2024 285 | > - Source code - https://godbolt.org/z/Kf9rovaqE (~100 LOC, C++17, gcc, clang, msvc, no dependencies) 286 | > 287 | > - How `mp` compares to Reflection for C++26 (https://wg21.link/P2996)? 288 | > 289 | > `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. 290 | > 291 | > | mp (C++20) | P2996 (C++26*) | 292 | > | - | - | 293 | > | `meta` | `^^T` | 294 | > | `using info = decltype(meta)` | `using info = decltype(^^::)` | 295 | > | `type_of` | `typename [: T :]` | 296 | > | `for_each` | `template for` (https://wg21.link/p1306) | 297 | > | `apply_t` | `substitute` | 298 | > | `invoke` | `reflect_invoke` | 299 | > | `invoke` | `test_trait` | 300 | > | `invoke` | `extract` | 301 | > 302 | > - Similar projects? 303 | > 304 | > [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) 305 | 306 | ### Resources 307 | 308 | > - https://wg21.link/P2996 (Reflection for C++26) 309 | > - https://github.com/seanbaxter/circle (Circle-lang) 310 | > - https://zig.guide/language-basics/comptime (Zig-comptime) 311 | 312 | ### License 313 | 314 | > - [MIT](LICENSE) 315 | 316 |