Boost Ext Mp Save

C++17 ~~Template~~ Meta-Programming library

Project README

Boost Licence Version build Try it online


MP - Template Meta-Programming

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

Features

Requirements

* Limited compiler support and functionality (see API)


Overview

static_assert(mp::meta<int> != mp::meta<void>);
static_assert(typeid(mp::meta<int>) == typeid(mp::meta<void>));
constexpr mp::meta_t 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;

https://godbolt.org/z/h5eacKPcY


Examples

[C++17] Hello world

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

https://godbolt.org/z/44q1jEsea


[C++17] Algorithms

template<class... Ts>
auto drop_1_reverse = [] {
  std::array v{mp::meta<Ts>...}; // or mp::array{mp::meta<Ts>...};
  std::array<mp::meta_t, sizeof...(Ts)-1> r{};
  // fuse operations for faster compilation times (can use STL)
  for (auto i = 1u; i < v.size(); ++i) { r[i-1] = v[v.size()-i]; }
  return r;
};

static_assert(std::is_same_v<std::variant<int, double>,
              decltype(mp::apply<std::variant>(drop_1_reverse<float, double, int>))>);

https://godbolt.org/z/fhahKPqK1


[C++17/C++20] Reduce

template<class... Ts>
constexpr auto reduce() {
  constexpr auto v = drop_1_reverse<Ts...>();
  mp::meta_t result = mp::meta<void>;
  mp::for_each<v>([&]<auto m> {
    if (using type = mp::type_of<m>; std::is_same_v<double, type>) {
      result = mp::meta<type*>;
    }
  });
  return result;
}

static_assert(std::is_same_v<double*,
              mp::type_of<reduce<float, double, int>()>>);

https://godbolt.org/z/KEEPoxKK5


[C++20] Ranges

template<class... Ts>
constexpr mp::vector drop_1_reverse =
    std::array{mp::meta<Ts>...}
  | std::views::drop(1)
  | std::views::reverse
  ;

static_assert(std::is_same_v<std::variant<int, double>,
              mp::apply_t<std::variant, drop_1_reverse<float, double, int>>>);

https://godbolt.org/z/93GTe7xGx


[C++20] Reflection (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 =
    reflect::reflect(f)
  | std::views::filter([](auto meta) { return meta->name() == "b" ; })
  | std::views::reverse
  ;

mp::for_each<v>([&]<auto meta>{
  std::cout << reflect::type_name<mp::type_of<meta>>() << '\n'; // prints bool
  std::cout << mp::value_of<meta>(f) << '\n';                   // prints true
});

auto&& t = mp::apply<std::tuple, v>(f);

std::apply([](auto... args) {
  ((std::cout << args << '\n'), ...); // prints true
}, t);

https://godbolt.org/z/s7ce6bh5d


[C++20] Simple Domain Specific Language (DSL)

int main() {
  using namespace dsl;
  constexpr auto v =
        type_list<int, const double, float>
      | filter([]<class T> { return not std::is_const_v<T>; })
      | transform([]<class T>() -> T* { })
      | reverse
      | take<1>
      ;

  static_assert(type_list<float*> == v);
}

https://godbolt.org/z/r936cErdd


[C++17] Run-time testing/debugging

template<class... Ts>
constexpr auto reverse() {
  std::array v{mp::meta<Ts>...};
  std::array<mp::meta_t, sizeof...(Ts)> r;
  for (auto i = 0u; i < v.size(); ++i) { r[i] = v[v.size()-i-1]; }
  return r;
}

int main() {
  static_assert(
    std::array{mp::meta<float>, mp::meta<double>, mp::meta<int>}
    ==
    reverse<int, double, float>()
  );

  assert((
    std::array{mp::meta<float>, mp::meta<double>, mp::meta<int>}
    ==
    reverse<int, double, float>()
  ));
}

https://godbolt.org/z/h9K3bnaea


API

/**
 * Meta type object representation
 */
using meta_t = /* unspecified */;
/**
 * Creates meta type
 *
 * @code
 * static_assert(meta<void> == meta<void>);
 * static_assert(meta<void> != meta<int>);
 * @endcode
 */
template<class T> inline constexpr meta_t meta = /* unspecified */;
/**
 * Returns underlying type from meta type
 *
 * @code
 * static_assert(typeid(type_of<meta<void>>)
                 ==
                 typeid(void));
 * @endcode
 */
template<meta_t meta> using type_of = /* unspecified */;
/**
 * Returns value of meta type
 *
 * @code
 * static_assert(42 = value_of_v<mp::meta<std::integral_constant<int, 42>>>);
 * @endcode
 */
template<meta_t meta>
[[nodiscard]] constexpr auto value_of_v;
/**
 * Returns value of meta type underlying object
 */
template<meta_t meta, class T>
[[nodiscard]] constexpr decltype(auto) value_of(T&& t);
/**
 * Minimal (not standard compliant) array
 * implementation optimized for fast compilation-times with meta_t
 *
 * @code
 * array v{meta<void>, meta<int>};
 * assert(2 == v.size());
 * assert(meta<void> == v[0]);
 * assert(meta<int> == v[1]);
 * @endcode
 */
template<class T, size_t Size>
struct array;
/**
 * Minimal (not standard compliant) inplace/static vector
 * implementation optimized for fast compilation-times with meta_t
 *
 * @code
 * vector v{meta<void>, meta<int>};
 * assert(2 == v.size());
 * assert(meta<void> == v[0]);
 * assert(meta<int>  == v[1]);
 * @endcode
 */
template<class T, size_t Size> struct vector;
/**
 * Applies invocable `[] { return vector<meta_t>{...}; }` to
 *                   `T<type_of<meta_t>...>`
 *
 * @code
 * static_assert(typeid(variant<int>)
 *               ==
 *               typeid(apply<variant>([] { return vector{meta<int>}; })));
 * @endcode
 */
template<template<class...> class T, class Expr>
[[nodiscard]] constexpr auto apply(Expr expr);
/**
 * Applies expression expr to `R<type_of<meta_t>...>`
 *
 * @code
 * static_assert(typeid(variant<int>)
 *               ==
 *               typeid(apply<variant>([] { return vector{meta<int>}; })));
 * @endcode
 */
template<template<class...> class R, class Expr>
[[nodiscard]] constexpr auto apply(Expr expr);
/**
 * Applies vector V to `R<type_of<meta_t>...>`
 *
 * @code
 * static_assert(typeid(variant<int>)
 *               ==
 *               typeid(apply<variant, vector{meta<int>}>));
 * @endcode
 */
#if (__cpp_nontype_template_args >= 201911L)
template<template<class...> class R, auto V>
inline constexpr auto apply_v = /* unspecified */;
/**
 * Applies vector V with object t to `R{value_of<V>(t)...}
 */
#if (__cpp_nontype_template_args >= 201911L)
template<template<class...> class R, auto V, class T>
[[nodiscard]] constexpr auto apply(T&& t);
#endif
/**
 * Alternative to write `decltype(apply_v<T, Expr>))`
 *
 * @code
 * static_assert(typeid(variant<int>)
 *               ==
 *               typeid(apply_t<variant, [] { return vector{meta<int>}; }>));
 * @endcode
 */
#if (__cpp_nontype_template_args >= 201911L)
template<template<class...> class T, auto V> using apply_t = /* unspecified */;
#endif
/**
 * Iterates over all elements of constexpr continer
 *
 * @code
 * constexpr vector v{meta<int>};
 * for_each<v>([]<meta_t m> {
 *   static_assert(typeid(int) == typeid(type_of<m>));
 * });
 * @endcode
 */
#if (__cpp_generic_lambdas >= 201707L)
template<auto V, class Fn>
constexpr void for_each(Fn fn);
#endif

Configuration

#define MP 1'0'0 // Current library version (SemVer)

Benchmarks

To build/run benchmarks

git clone https://github.com/boost-ext/mp
git co benchmark
cd benchmark
mkdir build && cd build
cmake ..
make benchmark

Results (https://godbolt.org/z/6KzzEMGbe)


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.

  • Can I disable running tests at compile-time for faster compilation times?

    When DISABLE_STATIC_ASSERT_TESTS is defined static_asserts tests won't be executed upon inclusion. Note: Use with caution as disabling tests means that there are no gurantees upon inclusion that given compiler/env combination works as expected.

  • How to integrate with CMake/CPM?

    CPMAddPackage(
      Name mp
      GITHUB_REPOSITORY boost-ext/mp
      GIT_TAG v1.1.0
    )
    add_library(mp INTERFACE)
    target_include_directories(mp SYSTEM INTERFACE ${mp_SOURCE_DIR})
    add_library(mp::mp ALIAS mp)
    
    target_link_libraries(${PROJECT_NAME} mp::mp);
    
  • Similar projects?

    boost.mp11, boost.hana, boost.mpl


Disclaimer mp is not an official Boost library.

Open Source Agenda is not affiliated with "Boost Ext Mp" Project. README Source: boost-ext/mp
Stars
195
Open Issues
0
Last Commit
2 weeks ago
Repository

Open Source Agenda Badge

Open Source Agenda Rating