https://github.com/jonathanpoelen/jln.mp
C++17 meta programming library for fast compilation speed.
https://github.com/jonathanpoelen/jln.mp
cpp cpp17 metaprogramming mpl template-metaprogramming
Last synced: 19 days ago
JSON representation
C++17 meta programming library for fast compilation speed.
- Host: GitHub
- URL: https://github.com/jonathanpoelen/jln.mp
- Owner: jonathanpoelen
- License: mit
- Created: 2019-06-08T22:00:45.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2026-01-25T02:35:06.000Z (2 months ago)
- Last Synced: 2026-01-25T16:20:16.294Z (2 months ago)
- Topics: cpp, cpp17, metaprogramming, mpl, template-metaprogramming
- Language: C++
- Homepage: https://jonathanpoelen.github.io/jln.mp/
- Size: 15.1 MB
- Stars: 11
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://github.com/jonathanpoelen/jln.mp/actions?query=workflow%3ACI)
# Jln.Mp: A C++17 metaprogramming library
[Jln.mp](https://github.com/jonathanpoelen/jln.mp) is a C++17 metaprogramming library designed for fast compilation speed (strongly inspired by [Kvasir::mpl](https://github.com/kvasir-io/mpl), but generally faster, with more algorithm and a debug mode to have errors with more context).
Licence: MIT
Online documentation: https://jonathanpoelen.github.io/jln.mp/
Online documentation for v1: https://jonathanpoelen.github.io/jln.mp/v1/
Single file version in [standalone branch](https://github.com/jonathanpoelen/jln.mp/tree/standalone).
## Concepts
Functions of jln.mp are used in 2 stages:
- Instantiation, by indicating parameters which describe how it must work.
- Call, by applying sequence to an instantiation.
For example, suppose we want to remove `void` from a sequence. The function to use is `jln::mp::remove`:
```cpp
using remove_void = jln::mp::remove;
```
We can then apply it to our data:
```cpp
using result = jln::mp::call;
// result == jln::mp::list
```
Now suppose that `result` must be a `std::tuple`. Rather than linking with another function, it is possible to combine them in `remove_void` via a continuation (`C` parameter).
```cpp
using remove_void = jln:mp::remove>;
using result = jln::mp::call;
// result == std::tuple
```
The default continuations are `jln::mp::listify` which transforms a sequence into a `jln::mp::list` and `jln::mp::identity` which returns the input value.
Jln.mp also has 2 additional namespaces:
- `smp` a SFINAE compatible version of `mp`.
- `emp` which directly returns a result without going through `jln::mp::call`. According to the function, type sequences are replaced by lists and continuations are not always available.
### Create a function
A function is a type with a `f` template member.
```cpp
struct to_tuple
{
template
using f = std::tuple;
};
jln::mp::call == std::tuple
```
In the mind of the library, functions should at least take a continuation.
```cpp
// equivalent to jln::mp::cfe
template
struct to_tuple
{
template
using f = jln::mp::call>;
};
jln::mp::call, int, double> == std::tuple
```
## Glossary
- Sequence: a value sequence or a type sequence.
- Set: a sequence of unique elements.
- Map: a sequence of lists having at least one element (the key). The keys of the map must be unique.
- Value: a type with a `value` member.
- Typelist: an instance compatible with `template class T`, such as `list<>`.
- Function: a type with a `f` template member. The number and the nature of the parameters depend on the context of use.
- Predicate: a function which takes n argument (usually 1) and returns a boolean.
- Meta-function: a template class `template class M`.
- Lazy meta-function: a meta-function with a `type` member.
- `C`: Continuation function. Represents the function used to chain calls, typically `listify` or `identity`.
- `TC` parameter: True Continuation function. Represents a continuation used when something is found or true.
- `FC` parameter: False Continuation function. Represents a continuation used when something is not found or false.
- `_v` suffix: `C::f` takes values. Usually `C::f` (C++17) or `C::f` (C++20). In the `emp` namespace, with a few exceptions, this corresponds to a variable template (as for the stl).
- `_c` suffix: parameters are number values rather than types. Usually `foo_c = foo>`.
## Example of real life
Implementation of `std::tuple_cat` that works with tuple like.
```cpp
#include "jln/mp/algorithm/make_int_sequence.hpp"
#include "jln/mp/algorithm/transform.hpp"
#include "jln/mp/algorithm/repeat.hpp"
#include "jln/mp/algorithm/repeat_index.hpp"
#include "jln/mp/functional/each.hpp"
#include "jln/mp/functional/continuation.hpp"
#include "jln/mp/list/join.hpp"
#include
#include
namespace mp = jln::mp;
namespace emp = jln::mp::emp;
/*
* tuple_cat() implementation
*/
//@{
template
struct my_tuple_element
{
template
using f = std::tuple_element_t;
};
template
using my_tuple_cat_result_type = mp::call<
// Convert a sequence of mp::list to std::tuple
mp::join>,
// Convert a tuple like to mp::list of tuple element.
// To support tuple-likes, it is necessary to use std::tuple_size and std::tuple_element.
// Otherwise, emp::unpack is sufficient.
emp::make_int_sequence<
std::tuple_size>,
// Convert a sequence of tuple index to a mp::list of tuple element.
mp::transform>>
>...
>;
template
constexpr R my_tuple_cat_impl(
emp::numbers, emp::numbers, Tuple t)
{
// get is looked up by argument-dependent lookup
using std::get;
return R{ get(get(std::move(t)))... };
}
template>
constexpr R my_tuple_cat(Tuples&&... args)
{
// tuple_size_v: 3 2 4
// list< 0, 0, 0, 1, 1, 2, 2, 2, 2 >
using index_by_tuple = mp::repeat_index_v_c>
::f>...>;
// tuple_size_v: 3 2 4
// list< 0, 1, 2, 0, 1, 0, 1, 2, 3 >
using index_by_value = emp::join<
emp::make_int_sequence>>...
>;
return my_tuple_cat_impl(index_by_tuple{}, index_by_value{},
std::tuple(std::forward(args)...));
}
/*
* Tuple like class
*/
//@{
namespace toy
{
// tuple like
struct Vector2D
{
int x, y;
};
template
constexpr int get(Vector2D const& t)
{
return i == 0 ? t.x : t.y;
}
}
template<>
struct std::tuple_size<::toy::Vector2D>
: std::integral_constant
{};
template
struct std::tuple_element
{
using type = int;
};
//@}
/*
* Test
*/
// @{
constexpr std::tuple t0{1, 2, 3};
constexpr std::tuple t1{4, 5};
constexpr std::tuple t2{6};
constexpr std::array a{7, 8, 9, 10};
constexpr toy::Vector2D v {11, 12};
constexpr auto my_tuple = my_tuple_cat(t0, t1, t2, a, v);
using my_tuple_type = std::remove_const_t;
using std_tuple = std::tuple<
int, float, double,
char, unsigned,
long,
short, short, short, short,
int, int>;
static_assert(std::is_same_v);
static_assert(my_tuple == std::tuple{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
// @}
```
## FAQ
> Functions are missing in the stacktrace when the compiler displays an error message, how to display them?
Compile with the define `JLN_MP_DEBUG` at `1` to have errors with more context.
> Error: `sorry, unimplemented: mangling record_type` or `sorry, unimplemented: mangling typename_type` with Gcc.
This is a [Gcc bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95299) when an algorithm is used in the prototype of a function.
```cpp
template
mp::call foo();
// Must be replaced by
template>
R foo();
```