{"id":34531302,"url":"https://github.com/jonathanpoelen/jln.mp","last_synced_at":"2026-03-14T02:33:49.545Z","repository":{"id":149645434,"uuid":"190939187","full_name":"jonathanpoelen/jln.mp","owner":"jonathanpoelen","description":"C++17 meta programming library for fast compilation speed.","archived":false,"fork":false,"pushed_at":"2026-01-25T02:35:06.000Z","size":15841,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-25T16:20:16.294Z","etag":null,"topics":["cpp","cpp17","metaprogramming","mpl","template-metaprogramming"],"latest_commit_sha":null,"homepage":"https://jonathanpoelen.github.io/jln.mp/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonathanpoelen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-06-08T22:00:45.000Z","updated_at":"2026-01-25T02:35:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"2561dff4-254f-432a-8f1b-4edad4daa8e9","html_url":"https://github.com/jonathanpoelen/jln.mp","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jonathanpoelen/jln.mp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanpoelen%2Fjln.mp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanpoelen%2Fjln.mp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanpoelen%2Fjln.mp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanpoelen%2Fjln.mp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonathanpoelen","download_url":"https://codeload.github.com/jonathanpoelen/jln.mp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanpoelen%2Fjln.mp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30485986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-14T01:54:10.014Z","status":"online","status_checked_at":"2026-03-14T02:00:06.612Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp17","metaprogramming","mpl","template-metaprogramming"],"created_at":"2025-12-24T05:38:47.520Z","updated_at":"2026-03-14T02:33:49.537Z","avatar_url":"https://github.com/jonathanpoelen.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/jonathanpoelen/jln.mp/actions/workflows/ci.yml/badge.svg)](https://github.com/jonathanpoelen/jln.mp/actions?query=workflow%3ACI)\n\n# Jln.Mp: A C++17 metaprogramming library\n\n[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).\n\nLicence: MIT\n\nOnline documentation: https://jonathanpoelen.github.io/jln.mp/\n\nOnline documentation for v1: https://jonathanpoelen.github.io/jln.mp/v1/\n\nSingle file version in [standalone branch](https://github.com/jonathanpoelen/jln.mp/tree/standalone).\n\n## Concepts\n\nFunctions of jln.mp are used in 2 stages:\n\n- Instantiation, by indicating parameters which describe how it must work.\n- Call, by applying sequence to an instantiation.\n\nFor example, suppose we want to remove `void` from a sequence. The function to use is `jln::mp::remove`:\n\n```cpp\nusing remove_void = jln::mp::remove\u003cvoid\u003e;\n```\n\nWe can then apply it to our data:\n\n```cpp\nusing result = jln::mp::call\u003cremove_void, int, void, double, char\u003e;\n// result == jln::mp::list\u003cint, double, char\u003e\n```\n\nNow 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).\n\n```cpp\nusing remove_void = jln:mp::remove\u003cvoid, /*C=*/jln::mp::cfe\u003cstd::tuple\u003e\u003e;\n\nusing result = jln::mp::call\u003cremove_void, int, void, double, char\u003e;\n// result == std::tuple\u003cint, double, char\u003e\n```\n\nThe default continuations are `jln::mp::listify` which transforms a sequence into a `jln::mp::list` and `jln::mp::identity` which returns the input value.\n\n\nJln.mp also has 2 additional namespaces:\n\n- `smp` a SFINAE compatible version of `mp`.\n- `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.\n\n\n### Create a function\n\nA function is a type with a `f` template member.\n\n```cpp\nstruct to_tuple\n{\n  template\u003cclass... xs\u003e\n  using f = std::tuple\u003cxs...\u003e;\n};\n\njln::mp::call\u003cto_tuple, int, double\u003e == std::tuple\u003cint, double\u003e\n```\n\nIn the mind of the library, functions should at least take a continuation.\n\n```cpp\n// equivalent to jln::mp::cfe\u003cstd::tuple, C\u003e\ntemplate\u003cclass C = jln::mp::identity\u003e\nstruct to_tuple\n{\n  template\u003cclass... xs\u003e\n  using f = jln::mp::call\u003cC, std::tuple\u003cxs...\u003e\u003e;\n};\n\njln::mp::call\u003cto_tuple\u003c\u003e, int, double\u003e == std::tuple\u003cint, double\u003e\n```\n\n\n## Glossary\n\n- Sequence: a value sequence or a type sequence.\n- Set: a sequence of unique elements.\n- Map: a sequence of lists having at least one element (the key). The keys of the map must be unique.\n- Value: a type with a `value` member.\n- Typelist: an instance compatible with `template\u003cclass...\u003e class T`, such as `list\u003c\u003e`.\n- Function: a type with a `f` template member. The number and the nature of the parameters depend on the context of use.\n- Predicate: a function which takes n argument (usually 1) and returns a boolean.\n- Meta-function: a template class `template\u003cclass...\u003e class M`.\n- Lazy meta-function: a meta-function with a `type` member.\n- `C`: Continuation function. Represents the function used to chain calls, typically `listify` or `identity`.\n- `TC` parameter: True Continuation function. Represents a continuation used when something is found or true.\n- `FC` parameter: False Continuation function. Represents a continuation used when something is not found or false.\n- `_v` suffix: `C::f` takes values. Usually `C::f\u003cjln::mp::int_t...\u003e` (C++17) or `C::f\u003cauto...\u003e` (C++20). In the `emp` namespace, with a few exceptions, this corresponds to a variable template (as for the stl).\n\n- `_c` suffix: parameters are number values rather than types. Usually `foo_c\u003cint_t i\u003e = foo\u003cnumber\u003ci\u003e\u003e`.\n\n\n## Example of real life\n\nImplementation of `std::tuple_cat` that works with tuple like.\n\n```cpp\n#include \"jln/mp/algorithm/make_int_sequence.hpp\"\n#include \"jln/mp/algorithm/transform.hpp\"\n#include \"jln/mp/algorithm/repeat.hpp\"\n#include \"jln/mp/algorithm/repeat_index.hpp\"\n#include \"jln/mp/functional/each.hpp\"\n#include \"jln/mp/functional/continuation.hpp\"\n#include \"jln/mp/list/join.hpp\"\n\n#include \u003carray\u003e\n#include \u003ctuple\u003e\n\nnamespace mp = jln::mp;\nnamespace emp = jln::mp::emp;\n\n/*\n * tuple_cat() implementation\n */\n\n//@{\ntemplate\u003cclass Tuple\u003e\nstruct my_tuple_element\n{\n    template\u003cclass I\u003e\n    using f = std::tuple_element_t\u003cI::value, Tuple\u003e;\n};\n\ntemplate\u003cclass... Tuples\u003e\nusing my_tuple_cat_result_type = mp::call\u003c\n    // Convert a sequence of mp::list to std::tuple\n    mp::join\u003cmp::cfe\u003cstd::tuple\u003e\u003e,\n    // Convert a tuple like to mp::list of tuple element.\n    // To support tuple-likes, it is necessary to use std::tuple_size and std::tuple_element.\n    // Otherwise, emp::unpack\u003cTuples\u003e is sufficient.\n    emp::make_int_sequence\u003c\n        std::tuple_size\u003cstd::decay_t\u003cTuples\u003e\u003e,\n        // Convert a sequence of tuple index to a mp::list of tuple element.\n        mp::transform\u003cmy_tuple_element\u003cstd::decay_t\u003cTuples\u003e\u003e\u003e\n    \u003e...\n\u003e;\n\ntemplate\u003cclass R, mp::int_t... ituples, mp::int_t... ivalues, class Tuple\u003e\nconstexpr R my_tuple_cat_impl(\n    emp::numbers\u003cituples...\u003e, emp::numbers\u003civalues...\u003e, Tuple t)\n{\n    // get is looked up by argument-dependent lookup\n    using std::get;\n    return R{ get\u003civalues\u003e(get\u003cituples\u003e(std::move(t)))... };\n}\n\ntemplate\u003cclass... Tuples, class R = my_tuple_cat_result_type\u003cTuples...\u003e\u003e\nconstexpr R my_tuple_cat(Tuples\u0026\u0026... args)\n{\n    // tuple_size_v\u003cTuple\u003e:      3           2            4\n    // list\u003c                  0, 0, 0,     1, 1,     2, 2, 2, 2   \u003e\n    using index_by_tuple = mp::repeat_index_v_c\u003cmp::join\u003c\u003e\u003e\n        ::f\u003cstd::tuple_size_v\u003cstd::decay_t\u003cTuples\u003e\u003e...\u003e;\n\n    // tuple_size_v\u003cTuple\u003e:      3           2            4\n    // list\u003c                  0, 1, 2,     0, 1,     0, 1, 2, 3   \u003e\n    using index_by_value = emp::join\u003c\n        emp::make_int_sequence\u003cstd::tuple_size\u003cstd::decay_t\u003cTuples\u003e\u003e\u003e...\n    \u003e;\n\n    return my_tuple_cat_impl\u003cR\u003e(index_by_tuple{}, index_by_value{},\n        std::tuple\u003cTuples\u0026\u0026...\u003e(std::forward\u003cTuples\u003e(args)...));\n}\n\n\n/*\n * Tuple like class\n */\n\n//@{\nnamespace toy\n{\n    // tuple like\n    struct Vector2D\n    {\n        int x, y;\n    };\n\n    template\u003cstd::size_t i\u003e\n    constexpr int get(Vector2D const\u0026 t)\n    {\n        return i == 0 ? t.x : t.y;\n    }\n}\n\ntemplate\u003c\u003e\nstruct std::tuple_size\u003c::toy::Vector2D\u003e\n: std::integral_constant\u003cstd::size_t, 2\u003e\n{};\n\ntemplate\u003csize_t i\u003e\nstruct std::tuple_element\u003ci, ::toy::Vector2D\u003e\n{\n    using type = int;\n};\n//@}\n\n\n/*\n * Test\n */\n\n// @{\nconstexpr std::tuple\u003cint, float, double\u003e t0{1, 2, 3};\nconstexpr std::tuple\u003cchar, unsigned\u003e t1{4, 5};\nconstexpr std::tuple\u003clong\u003e t2{6};\nconstexpr std::array\u003cshort, 4\u003e a{7, 8, 9, 10};\nconstexpr toy::Vector2D v {11, 12};\n\nconstexpr auto my_tuple = my_tuple_cat(t0, t1, t2, a, v);\n\nusing my_tuple_type = std::remove_const_t\u003cdecltype(my_tuple)\u003e;\nusing std_tuple = std::tuple\u003c\n    int, float, double,\n    char, unsigned,\n    long,\n    short, short, short, short,\n    int, int\u003e;\n\nstatic_assert(std::is_same_v\u003cmy_tuple_type, std_tuple\u003e);\nstatic_assert(my_tuple == std::tuple{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});\n// @}\n```\n\n## FAQ\n\n\u003e Functions are missing in the stacktrace when the compiler displays an error message, how to display them?\n\nCompile with the define `JLN_MP_DEBUG` at `1` to have errors with more context.\n\n\u003e Error: `sorry, unimplemented: mangling record_type` or `sorry, unimplemented: mangling typename_type` with Gcc.\n\nThis 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.\n\n```cpp\ntemplate\u003cclass... Ts\u003e\nmp::call\u003cfunc, Ts...\u003e foo();\n\n// Must be replaced by\n\ntemplate\u003cclass... Ts, class R = mp::call\u003cfunc, Ts...\u003e\u003e\nR foo();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanpoelen%2Fjln.mp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathanpoelen%2Fjln.mp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanpoelen%2Fjln.mp/lists"}