Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

475 Commits

Repository files navigation

// Overview / Examples / API / FAQ / Resources

MP: Template Meta-Programming library

MIT LicenceVersionBuildTry it online

https://en.wikipedia.org/wiki/Template_metaprogramming

Features

Requirements

Overview

API (https://godbolt.org/z/zTdYGvKKW)

// mp::metastatic_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_ofconstexpr 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::applytemplate<class...> structtype_list{ };
static_assert(std::is_same_v<type_list<int>, mp::apply_t<type_list, std::array{meta}>>);
// mp::invokestatic_assert(not mp::invoke<std::is_const>(meta));
static_assert(std::is_same_v<constint, mp::type_of<mp::invoke<std::add_const>(meta)>>);
intmain() {
// mp::for_eachconstexprauto v = mp::vector{meta};
mp::for_each<v>([&]<mp::info meta>{ /* ... */ });
}
// and more (see API)...

Examples

Hello World (https://godbolt.org/z/69jGzqPs1)

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>>);

Algorithms (https://godbolt.org/z/GvzjvdPq8)

template<class... Ts>
structexample {
mp::apply_t<std::variant,
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)
| std::ranges::to<mp::vector<mp::info>>()
> v;
};
static_assert(
typeid(std::variant<constint, constshort>)
==
typeid(example<double, void, constshort, int>::v)
);

Reflection - https://github.com/qlibs/reflect (https://godbolt.org/z/qb37G79Ya)

structfoo {
int a;
bool b;
float c;
};
constexpr foo f{.a = 42, .b = true, .c = 3.2f};
constexpr mp::vector<mp::info> v =
members(f)
| std::views::filter([&](auto meta) { returnmember_name(meta, f) != "b"; })
;
static_assert(std::tuple{42, 3.2f} == to<std::tuple, v>(f));

Run-time testing/debugging (https://godbolt.org/z/vTfGGToa4)

constexprautoreverse(std::ranges::range auto v) {
std::reverse(v.begin(), v.end());
return v;
}
intmain() {
static_assert(
std::array{mp::meta<float>, mp::meta<double>, mp::meta<int>}
==
reverse(std::array{mp::meta<int>, mp::meta<double>, mp::meta<float>})
);
assert((
std::array{mp::meta<float>, mp::meta<double>, mp::meta<int>}
==
reverse(std::array{mp::meta<int>, mp::meta<double>, mp::meta<float>})
));
}

API

namespacemp::inline v2_0_11 {
/** * Meta info type*/enumclassinfo : size_t { };
/** * Creates meta type * * @code * static_assert(meta<void> == meta<void>); * static_assert(meta<void> != meta<int>); * @endcode*/template<classT> inlineconstexpr info meta = /* unspecified */;
/** * Returns underlying type from meta type * * @code * static_assert(typeid(type_of<meta<void>>) == typeid(void)); * @endcode*/template<info meta> using type_of = /* unspecified */;
/** * Applies invocable `[] { return vector<info>{...}; }` to * `T<type_of<info>...>` * * @code * static_assert(typeid(variant<int>) == * typeid(apply<variant>([] { return vector{meta<int>}; }))); * @endcode*/template<template<class...> classT>
[[nodiscard]]constexprautoapply(concepts::invocable auto expr);
/** * Applies range to `T<type_of<info>...>` * * @code * static_assert(typeid(variant<int>) == * typeid(apply<variant, vector{meta<int>}>)); * @endcode*/template<template<class...> classT, concepts::range auto range>
inlineconstexprauto apply_v = decltype(apply<T, [] { return range; }>);
/** * Applies range to `T<type_of<info>...>` * * @code * static_assert(typeid(variant<int>) == * typeid(apply_t<variant, [] { return vector{meta<int>}; }>)); * @endcode*/template<template<class...> classT, concepts::range auto range>
usingapply_t = decltype(apply_v<T, range>);
/** * Invokes function with compile-time info based on meta-info * * @code * static_assert(invoke( * []<info m> { return std::is_const_v<type_of<m>>; * }, meta<conts int>)); * @endcode*/[[nodiscard]]constexprautoinvoke(auto&& fn, info meta);
/** * Invokes type_trait with meta-info * * @code * static_assert(not invoke<std::is_const>(meta<int>)); * static_assert(invoke<std::is_const>(meta<const int>)); * @endcode*/template<template<class...> classT, class... Ts>
[[nodiscard]]constexprautoinvoke(info meta);
/** * unrolls fn N times # optionally passes index I to fn * @code * mp::unroll<3>([]{ std::print("mp"); }); // prints 'mpmpmp' * mp::unroll<3>([]<auto I>{ std::print("{}", I); }); // prints '012' * @endcode*/template<size_t N>
inlineconstexprautounroll(auto&& fn);
/** * Iterates over all elements of a range * * @code * constexpr vector v{meta<int>}; * for_each<v>([]<info m> { * static_assert(typeid(int) == typeid(type_of<m>)); * }); * @endcode*/template<concepts::range auto range>
inlineconstexprautofor_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

  • 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>^^T
    using info = decltype(meta<void>)using info = decltype(^^::)
    type_of<T>typename [: T :]
    for_eachtemplate for (https://wg21.link/p1306)
    apply_tsubstitute
    invoke<Fn>reflect_invoke
    invoke<Trait>test_trait
    invoke<T>extract
  • Similar projects?

    boost.mp11, boost.hana, boost.fusion, boost.mpl

Resources

License

About

C++20 Meta-Programming library

Topics

Resources

Stars

317 stars

Watchers

13 watching

Forks

Releases

Used by

Contributors

Languages