# Meta-Programming is one of the C++ super-powers

Traditional meta-programming model in C++ is very powerful but not the easiest to grasp. Mainly because it has different syntax than 'normal' C++ with a lot of angle brackets, it's functional, immutable, etc.

There are some great template meta-programming libraries available such as boost.mp11 - https://www.boost.org/doc/libs/1_85_0/libs/mp11/doc/html/mp1... which make template meta-programming much simpler.
The question is - Can we do better? And if so, what are the trade-offs? All in all, wouldn't be great to be able to write the same code for run-time and compile-time and/or debug compile-time code at run-time?

Reflection for C++ - https://wg21.link/P2996 - introduced a new meta-programming model which is value/consteval based and can greatly improve the experience. Together with reflection is a very powerful combination but it also has its own set of trade-offs such as slower compilation-times.

This post is about `mp` - https://github.com/boost-ext/mp - meta-programming library which supports - similar to P2996 - meta-programming model for easier transition as it supports C++20 (msvc, gcc, clang), has a bit faster compilation times than P2996, but mostly, it makes meta-programming a 'normal' C++. In the mp world no difference between run-time and compile-time, whole standard library can be leveraged and it has reflection integration with C++20 using https://github.com/boost-ext/reflect. Of course it has it own set of trade-offs but, IMHO, it has a lot of potential and it's super fan.

> Example (API)

// mp::meta
static_assert(mp::meta<int> == mp::meta<int>);
static_assert(mp::meta<int> != mp::meta<void>);
static_assert(typeid(mp::meta<int>) == typeid(mp::meta<void>));

// mp::type_of
constexpr mp::info meta = mp::meta<int>;
mp::type_of<meta> i{}; // same as int i{};
mp::type_of<mp::meta<bool>> b = true; // same as bool b = true;

// mp::apply
template<class...> struct type_list{ };
static_assert(std::is_same_v<type_list<int, int>, mp::apply_t<type_list, mp::array{meta, meta}>>);

// mp::invoke
static_assert(not mp::invoke<std::is_const>(meta));
static_assert(std::is_same_v<const int, mp::type_of<mp::invoke<std::add_const>(meta)>>);

// hello world
template<size_t N, class... Ts>
using at_c = mp::type_of<std::array{mp::meta<Ts>...}[N]>;

static_assert(std::is_same_v<int, at_c<0, int, bool, float>>);
static_assert(std::is_same_v<bool, at_c<1, int, bool, float>>);
static_assert(std::is_same_v<float, at_c<2, int, bool, float>>);

// ranges
template<class... Ts>
constexpr mp::vector ranges =
std::array{mp::meta<Ts>...}
| std::views::drop(1)
| std::views::reverse
| std::views::filter([](auto m) { return mp::invoke<std::is_integral>(m); })
| std::views::transform([](auto m) { return mp::invoke<std::add_const>(m); })
| std::views::take(2)
;

static_assert(std::is_same_v<
std::variant<const int, const short>,
mp::apply_t<std::variant, ranges<double, void, const short, int>>
>);

// reflection (requires https://github.com/boost-ext/reflect)
struct foo {
int a;
bool b;
float c;
};

foo f{.a = 42, .b = true, .c = 3.2f};

constexpr mp::vector v = reflexpr(f)
| std::views::filter([&](auto meta) { return member_name(meta, f) != "b"; })
;

static_assert(std::tuple{42, 3.2f} == unreflexpr<std::tuple, v>(f));

> Full example - standalone - https://godbolt.org/z/Mjcxedzzj

> Full example - reflection - https://godbolt.org/z/ds3KMGhqP

> Library - https://github.com/boost-ext/mp

> Supported compilers - https://godbolt.org/z/qarWdbK79

> Compilation times benchmark - https://boost-ext.github.io/mp