{"id":15429731,"url":"https://github.com/ldionne/mpl11","last_synced_at":"2025-10-07T05:38:39.903Z","repository":{"id":4587271,"uuid":"5729431","full_name":"ldionne/mpl11","owner":"ldionne","description":"Enjoy template metaprogramming","archived":false,"fork":false,"pushed_at":"2016-12-17T20:56:49.000Z","size":5595,"stargazers_count":113,"open_issues_count":7,"forks_count":10,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-15T22:54:28.193Z","etag":null,"topics":["cpp","cpp11","cpp14","template-metaprogramming"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ldionne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-09-08T15:21:15.000Z","updated_at":"2024-09-25T18:11:15.000Z","dependencies_parsed_at":"2022-09-08T09:42:17.294Z","dependency_job_id":null,"html_url":"https://github.com/ldionne/mpl11","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ldionne/mpl11","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldionne%2Fmpl11","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldionne%2Fmpl11/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldionne%2Fmpl11/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldionne%2Fmpl11/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ldionne","download_url":"https://codeload.github.com/ldionne/mpl11/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ldionne%2Fmpl11/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278725119,"owners_count":26034941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"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","cpp11","cpp14","template-metaprogramming"],"created_at":"2024-10-01T18:12:41.151Z","updated_at":"2025-10-07T05:38:39.863Z","avatar_url":"https://github.com/ldionne.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MPL11\n\u003e Enjoy template metaprogramming\n\n## Disclaimers\nThis is not an official Boost library. It might be proposed as a successor\nfor the current Boost.MPL in the future, but there is no guarantee. Also, I\nam currently working on [Boost.Hana][hana_github], a library which tries to\nmerge MPL11 and Boost.Fusion into a single library. If that works out, it\nwould probably replace the MPL11.\n\nThe library is unstable at the moment; do not use for production.\n\nThis was initially supposed to be a simple C++11 reimplementation of the\nBoost.MPL. However, for reasons documented in the [rationales](#rationales),\nthe library was redesigned and the name does not fit so well anymore.\n\n\n## Table of contents\n- [Installation](#installation)\n- [Introduction](#introduction)\n- [Metafunctions](#metafunctions)\n  + [Boxed types](#boxed-types)\n  + [Laziness](#laziness)\n  + [Lifted metafunctions](#lifted-metafunctions)\n- [Datatypes and data constructors](#datatypes-and-data-constructors)\n  + [Boxed data constructors](#boxed-data-constructors)\n  + [Laziness in data constructors](#laziness-in-data-constructors)\n  + [Conversions](#conversions)\n- [Methods](#methods)\n- [Typeclasses](#typeclasses)\n- [Rewrite rules](#rewrite-rules)\n- [Acknowledgements](#acknowledgements)\n- [Rationales](#rationales)\n- [Todo list](#todo-list)\n\n\n## Installation\nThe MPL11 is a header only library. To use it in your own project, just add the\n[include](include) directory to your compiler's header search path and you are\ndone.\n\nThe library has no dependencies - not even the standard library. However,\nit requires a C++14-able compiler. The test suite passes under the following\ncompilers:\n- clang version 3.4\n- clang version 3.5.0\n- GCC 4.9.0 20140302 (experimental)\n- Apple LLVM version 5.1 (clang-503.0.38)\n\nTo compile the unit tests, you will also need [CMake][]. Once you have it, you\ncan go to the root of the project and do:\n\n```shell\n$ mkdir build\n$ cd build\n$ cmake ..\n$ make tests    # Compiles the unit tests.\n```\n\n### Minified version\nA minified version of the library is also provided. To use it, simply include\nthe `boost/mpl11.min.hpp` header, which contains the whole library. Note that\nthe minified header must not be used in conjunction with other headers from\nthe library.\n\n\n## Introduction\nThe MPL11 is a C++11 library providing composable, high-level primitives for\nsolving complex [template metaprogramming][wiki-tmp] problems. The library is\nbuilt around a few core concepts; the aim of this tutorial is to present them,\nwhile the handful of tools provided by the library are left to the\n[reference documentation][doxygen-doc].\n\nThis tutorial assumes a good understanding of template metaprogramming and\nbasic functional programming concepts. Also, a good understanding of the\n[Boost.MPL][] library will be helpful. However, the MPL11 diverges from the\nBoost.MPL in many ways, and one should be careful not to transfer knowledge\nbetween both libraries without checking the documentation.\n\n\n## Metafunctions\nInformally, a metafunction is a template representing a compile-time function\ntaking types as arguments and returning a type as a result. Readers coming\nfrom the MPL should be careful here, since the formal definition differs\nfrom that of the MPL.\n\nFormally, let `f` be a C++ template with an arbitrary number of type\ntemplate parameters, and type template parameters only. Then, `f` is a\n__metafunction__ if and only if there exists types `x1, ..., xn` such\nthat `f\u003cx1, ..., xn\u003e::type` is a valid type name. In this context,\n\n- `x1, ..., xn` are the __arguments__ of `f`.\n- Forming a specialization `f\u003cx1, ..., xn\u003e` is called __suspending__ `f`\n  with `x1, ..., xn`.\n- A specialization `f\u003cx1, ..., xn\u003e` is called a __thunk__ or a __suspension__.\n- The nested `::type` of a thunk is called the __result__ of the thunk. If the\n  thunk is of the form `f\u003cx1, ..., xn\u003e`, we can also say it is the __result__\n  of `f` with `x1, ..., xn`.\n- Fetching the result of a thunk is called __evaluating__ the thunk. If the\n  thunk is of the form `f\u003cx1, ..., xn\u003e`, we can also say __invoking__ `f`\n  with `x1, ..., xn` or __applying__ `f` to `x1, ..., xn`.\n- The __arity__ of a metafunction is the number of arguments it can be\n  invoked with. A metafunction with arity _n_ is said to be a __n-ary__\n  metafunction.\n- A metafunction that can be invoked with any number of arguments is said\n  to be __variadic__. By definition, a variadic metafunction is n-ary for\n  any non-negative integer n.\n\nIt is important to note the difference between this definition and the one\ngiven by the Boost.MPL. With this definition, a metafunction can never be a\nnormal C++ type; it must always be a template. Hence, Boost.MPL nullary\nmetafunctions implemented as non-template classes are not considered as\nmetafunctions. Here are some examples:\n\n```cpp\n// A unary metafunction.\ntemplate \u003ctypename x\u003e\nstruct unary { struct type; };\n\n// A binary metafunction.\ntemplate \u003ctypename x, typename y\u003e\nstruct binary { struct type; };\n\n// A variadic metafunction.\ntemplate \u003ctypename ...\u003e\nstruct variadic { struct type; };\n\n// A nullary metafunction. It can only be invoked with\n// 0 arguments, and it is therefore 0-ary (nullary).\ntemplate \u003ctypename ...\u003e struct nullary;\ntemplate \u003c\u003e struct nullary\u003c\u003e { struct type; };\n\n// Not a metafunction with the MPL11; it is not a template!\nstruct MPL_nullary { struct type; };\n\n// Not a metafunction; it never has a result (a nested ::type)!\ntemplate \u003ctypename ...\u003e\nstruct no_result { };\n```\n\n\n### Boxed types\nInformally, a boxed type is a type that has yet to be evaluated. Hence,\nbefore knowing the actual \"value\" of a boxed type, one must evaluate it,\na process which is called unboxing.\n\nFormally, for an arbitrary C++ type `T`, a __boxed `T`__ is an arbitrary C++\ntype `B` such that `B::type` is `T`. In this context, `B` is called a __box__\n(of `T`) and fetching the nested `::type` inside of `B` is called __unboxing__\n`T`.\n\n```cpp\nstruct T;\nstruct B { using type = T; }; // a boxed T (equivalently, a box of T)\n\nB::type; // unboxing T\n```\n\nConversely, wrapping an arbitrary type `T` in a type `B` such that `B::type`\nis `T` is called __boxing__ `T` (into `B` or with `B`). It is important to\nnote that `B` may depend on `T`, without which boxing would be of limited\ninterest.\n\n```cpp\nstruct T;\n\ntemplate \u003ctypename t\u003e\nstruct B { using type = t; };\n\nB\u003cT\u003e; // boxing T into B\n```\n\nNote that types may be boxed an arbitrary number of times. This is probably\nnot useful, but the definition is general enough to allow it.\n\n```cpp\nB\u003cB\u003cT\u003e\u003e; // this is a \"box of B\u003cT\u003e\", aka a \"box of (box of T)\"\n```\n\nThere exists a special boxed type named `undefined` (sometimes called\n_bottom_) which has the characteristic of causing a compile-time error\nwhen it is unboxed, even in SFINAE-able contexts. `undefined` can be\nseen as an invalid value, or the result of a computation that failed.\n\nHere are some examples to illustrate the previous definition:\n\n```cpp\n// This template takes an arbitrary type T and boxes it.\ntemplate \u003ctypename T\u003e\nstruct box {\n    using type = T;\n};\n\n// These are not boxed.\nclass x;\nstruct y { char foo; };\nchar;\nbox\u003cchar\u003e::type;\n\n// These are boxed types.\nbox\u003cchar\u003e;                          // a boxed `char`\nbox\u003cbox\u003cchar\u003e\u003e;                     // a boxed `box\u003cchar\u003e`\nbox\u003cbox\u003cchar\u003e\u003e::type;               // a boxed `char`\nstruct x { using type = char; };    // a boxed `char`\nstruct y { struct type; };          // a boxed `y::type`\nstruct z { using type = z; };       // self-referential? why not!\n```\n\nIt is important to note that there are many different representations for a\nboxed `T`. This makes equivalence between boxed types a bit tricky. Consider\nthe following:\n\n```cpp\nstruct T;\nstruct B1 { using type = T; }; // a boxed T\nstruct B2 { using type = T; }; // a boxed T too\n```\n\nCertainly, `B1` and `B2` are equivalent w.r.t. to the type they box since they\nboth box the same type `T`. However, `B1` and `B2` are _not_ equivalent w.r.t.\nthe C++ type system because they are different types. Now, this is important\nbecause it tells us that we can't use pattern matching to define a\nmetafunction taking a boxed type as an argument. Indeed, since the\nrepresentation of a boxed type is not unique, we can't know what form\nwill have our argument in advance, and therefore we can't pattern match.\nConsider the following:\n\n```cpp\n// B should be a boxed type.\ntemplate \u003ctypename B\u003e\nstruct f;\n\n// This should handle boxed chars, but we don't know\n// what a boxed char may look like!\ntemplate \u003c\u003e\nstruct f\u003c????\u003e {\n    // ...\n};\n```\n\nNow, we might be tempted to do the following:\n\n```cpp\n// box is the template that we defined earlier. It takes an\n// arbitrary type and boxes it.\ntemplate \u003c\u003e\nstruct f\u003cbox\u003cchar\u003e\u003e {\n    // ...\n};\n```\n\nBut then...\n\n```cpp\ntemplate \u003ctypename T\u003e\nstruct bad {\n    using type = T;\n};\n\n// works, as expected\nf\u003cbox\u003cchar\u003e\u003e::type;\n\n// does not work, even though bad\u003cchar\u003e is clearly a boxed char\nf\u003cbad\u003cchar\u003e\u003e::type;\n```\n\nInstead, we would have to do something more convoluted like:\n\n```cpp\ntemplate \u003ctypename T\u003e\nstruct f_impl;\n\ntemplate \u003c\u003e\nstruct f_impl\u003cchar\u003e {\n    using type = ...;\n};\n\ntemplate \u003ctypename B\u003e\nstruct f\n    : f_impl\u003ctypename B::type\u003e\n{ };\n\nf\u003cbox\u003cchar\u003e\u003e::type; // works\nf\u003cbad\u003cchar\u003e\u003e::type; // works too\n```\n\n\u003e It is interesting to note that boxed types and thunks share a lot. In\n\u003e fact, a thunk is nothing but a boxed type that was formed by _suspending_\n\u003e a metafunction. Hence, whenever a boxed type is expected, a thunk may be\n\u003e used instead.\n\n\n### Laziness\nThis section introduces the notion of laziness in the context of template\nmetaprograms and explains how it relates to the previous notions. This is\nby no means a rigorous treatment of the broader subject of evaluation\nstrategies, and knowledge of those concepts is expected.\n\nInformally, laziness is a property of a metafunction meaning that the\nmetafunction performs the least amount of work needed to give its result.\nIt requires the metafunction to only evaluate the expressions that are\nactually needed in its body, and to evaluate them no more than once.\n\nThe second point is called memoization and it is handled behind the scenes by\nthe compiler. While the C++ standard does not require compilers to memoize\ntemplate instantiations, this is always the case in practice. Consider:\n\n```cpp\ntemplate \u003ctypename x\u003e\nstruct f {\n  using type = x;\n};\n\nf\u003cint\u003e::type; // instantiate f\u003cint\u003e\nf\u003cint\u003e::type; // f\u003cint\u003e is already instantiated, nothing is done.\n```\n\nThe first point, however, must be handled manually when writing template\nmetaprograms.\n\n\u003e __TODO__\n\u003e Finish this section. Specifically, explain the following:\n\u003e\n\u003e - What is a lazy metafunction (mf classes follow from that)\n\u003e - The inverse of a lazy metafunction is a strict metafunction (broadly)\n\u003e - Lazy metafunctions must take boxed types, otherwise they would always\n\u003e   evaluate their arguments whether they are needed or not. This is\n\u003e   equivalent to call-by-name.\n\u003e - Strict metafunctions can take unboxed arguments, because they always\n\u003e   evaluate their arguments anyways. However, strict metafunctions can still\n\u003e   take boxed arguments and unbox them unconditionally; this is just a matter\n\u003e   of convention.\n\u003e - Metafunctions take boxed arguments by default in the MPL11.\n\u003e - Metafunctions are lazy by default (i.e. whenever possible) in the MPL11.\n\u003e - Strict metafunctions usually still take boxed arguments for consistency.\n\u003e - Some metafunctions don't follow the convention, and in this case this\n\u003e   behavior is documented.\n\u003e - Metafunctions that don't follow the convention do it because it's\n\u003e   necessary or because it's much easier to do such or such when breaking\n\u003e   the convention.\n\u003e - Why are lazy metafunctions useful?\n\u003e   This could use the `drop` metafunction of the old introduction.\n\u003e   Laziness often leads to increased expressiveness; for example it becomes\n\u003e   easy to define new control structures and infinite data structures.\n\u003e - Consider keeping the optional section on non-strictness.\n\n\u003c!--\n### Non-strictness\nCall-by-need is an evaluation strategy that is part of a larger family of\nevaluation strategies called non-strict evaluation. The goal of this section\nis to formalize this notion in the context of metafunctions. While it offers\nan interesting formalization, it can safely be skipped by the casual reader.\n\nLet's define what it means for a metafunction to be strict. A n-ary metafunction\n`f` taking boxed arguments only is __strict in its `i`-th argument__ if and only\nif evaluating `f\u003cx1, ..., xi-1, undefined, xi+1, ..., xn\u003e` is a compile-time\nerror for all sets of arguments `x1, ..., xn`. A metafunction is __strict__ if\nit is strict in all its arguments. Conversely, a metafunction that is not strict\nin its `i`-th argument is __non-strict in its `i`-th argument__, and a\nmetafunction that is not strict is __non-strict__. Note that all metafunctions\ntaking unboxed arguments are trivially strict; for all sets of arguments\n`x1, ..., xn` and for all `i`, evaluating\n`f\u003cx1, ..., xi-1, undefined::type, xi+1, ..., xn\u003e` is indeed a\ncompile-time error, since peeking into `undefined` is an error.\n\nThe intuition behind this definition is that if replacing the `i`-th argument by\n`undefined` yields an error for all choices of `x1, ..., xn`, the metafunction\nmust necessarily try to evaluate that `i`-th argument. Hence, one can think of\nstrictness in an argument as the fact that the metafunction always evaluates\nthis argument. Conversely, a metafunction that is non strict in the `i`-th\nargument is a metafunction that might or might not evaluate that argument; but\nthere must be at least one combination of arguments for which the `i`-th\nargument is not evaluated.\n\nGiven a fixed set of arguments `x1, ..., xk` and a n-ary metafunction `f`, it\nis also possible to consider the strictness of `f` with respect to an argument\n`y` that is not in `x1, ..., xk`. The strictness of `f` in `y` is defined as the\nstrictness in `y` of the metafunction created by partially applying `f` to\n`x1, ..., xk`. That way, strictness in an argument can be seen as depending on\nthe value of the other arguments. For example, consider the following `if_`\nmetafunction:\n\n```cpp\ntemplate \u003ctypename Condition, typename Then, typename Else\u003e\nstruct if_\n    : std::conditional\u003cCondition::type::value, Then, Else\u003e::type\n{ };\n```\n\n`if_` is strict in its first argument and non-strict in its second and third\narguments. Now, let `if_\u003cx\u003e` denote the (binary) metafunction created by\npartially applying `if_` to `x`. Then, we can further say that `if_\u003ctrue_\u003e`\nis strict in its first argument and non-strict in its second one. Similarly,\n`if\u003cfalse_\u003e` is non-strict in its first argument and strict in its second one.\nClearly, analyzing the strictness properties of a metafunction can quickly\nbecome overwhelming. For this reason, metafunctions with special or complicated\nstrictness characteristics should be documented clearly.\n\n\u003e Interested readers should consider reading [this][haskell-denot-semantics]\n\u003e for a detailed treatment of strict versus non-strict semantics. This is a\n\u003e much richer topic than what is exposed here, and can lead to worthwhile\n\u003e insights.\n --\u003e\n\nAt this point, it is probably helpful to clarify that returning from a lazy\nmetafunction is no different than returning from a strict metafunction. For\nexample, consider the following lazy metafunction implementing an `if`\nstatement:\n\n```cpp\ntemplate \u003ctypename Condition, typename Then, typename Else\u003e\nstruct if_ {\n    using Branch = std::conditional\u003cCondition::type::value, Then, Else\u003e::type;\n    using type = typename Branch::type;\n};\n```\n\nSince `if_` is lazy, its arguments are all boxed types. Here, we unbox\n`Branch` and return that instead of returning `Branch` itself. This way,\n`if_\u003cCondition, Then, Else\u003e` is a thunk and we can pass it to other lazy\nmetafunctions as-is:\n\n```cpp\n// A lazy metafunction.\ntemplate \u003ctypename x\u003e\nstruct f;\n\nusing result = f\u003c   if_\u003cCondition, Then, Else\u003e  \u003e::type;\n```\n\n If we had defined `if_` as follows\n\n```cpp\ntemplate \u003ctypename Condition, typename Then, typename Else\u003e\nstruct if_ {\n    using Branch = std::conditional\u003cCondition::type::value, Then, Else\u003e::type;\n    using type = Branch; // Note that we don't unbox Branch here\n};\n```\n\nthen `if_` would return a thunk and we would need to do the following instead:\n\n```cpp\nusing result = f\u003c   if_\u003cCondition, Then, Else\u003e::type    \u003e::type;\n                                              ^^^^^^\n```\n\n\n### Lifted metafunctions\nInformally, a lifted metafunction is a representation of a metafunction that\nallows it to be manipulated as a first class citizen in template metaprograms.\nFormally, an arbitrary C++ type `f` is a __lifted metafunction__ if and only\nif `f::apply` is a metafunction. In general, lifted metafunctions inherit the\nterminology of metafunctions, and the characteristics of a lifted metafunction\nfollow from that of its nested `apply` metafunction. For example, the arity of\na lifted metafunction `f` is that of `f::apply`.\n\n\u003e The definition of a lifted metafunction is almost the same as the definition\n\u003e of a metafunction class in the Boost.MPL. The only difference is the\n\u003e difference between metafunctions in both libraries.\n\nHere are some examples of lifted metafunctions:\n\n```cpp\n// A unary lifted metafunction.\nstruct unary {\n    template \u003ctypename x\u003e\n    struct apply { struct type; };\n};\n\n// A binary lifted metafunction.\nstruct binary {\n    template \u003ctypename x, typename y\u003e\n    struct apply { struct type; };\n};\n\n// A variadic lifted metafunction.\nstruct variadic {\n    template \u003ctypename ...\u003e\n    struct variadic { struct type; };\n};\n\n// A nullary lifted metafunction.\nstruct nullary {\n    template \u003ctypename ...\u003e struct apply;\n};\ntemplate \u003c\u003e struct nullary::apply\u003c\u003e { struct type; };\n\n// Not a lifted metafunction with the MPL11; its nested apply\n// is not a metafunction!\nstruct MPL_nullary {\n    struct apply { struct type; };\n};\n\n// Not a lifted metafunction; its nested apply never has a result!\nstruct no_result {\n    template \u003ctypename ...\u003e\n    struct apply { };\n};\n```\n\nAny metafunction can be lifted, and the MPL11 defines a template to do\njust that.\n\n```cpp\ntemplate \u003ctemplate \u003ctypename ...\u003e class f\u003e\nstruct lift {\n    template \u003ctypename ...xs\u003e\n    struct apply\n        : f\u003cxs...\u003e\n    { };\n};\n```\n\n\u003e `lift` is essentially the same as `quote` in the Boost.MPL. The name\n\u003e `lift` was preferred because of its relation to a _lift_ in category\n\u003e theory. For completeness, `lift` is actually an equivalence of categories\n\u003e between the category where objects are C++ types and morphisms are\n\u003e templates to the category where objects are C++ types and morphisms\n\u003e are structs with a nested `apply` template.\n\n\n## Datatypes and data constructors\nAt compile-time, a type becomes a value. A legitimate question would then be:\nwhat is the type of that value? In the MPL11, datatypes play that role.\nClosely related are data constructors, which are a way of creating values\nof a given datatype. For example, let's create a simple compile-time list:\n\n```cpp\n// A \"tag\" representing the datatype.\nstruct List;\n\n// The list constructor. It represents a value of type List that\n// contains the provided elements.\ntemplate \u003ctypename ...Elements\u003e\nstruct list { using mpl_datatype = List; };\n\n// The cons constructor. It represents a value of type List\n// with the provided head and tail.\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons { using mpl_datatype = List; };\n\n// The nil constructor. It represents an empty List.\nstruct nil { using mpl_datatype = List; };\n```\n\nData constructors must provide a nested `::mpl_datatype` alias representing\ntheir datatype. One can then use the `datatype` metafunction to retrieve it:\n\n```cpp\ndatatype\u003cnil\u003e::type; // == List\n```\n\nIt is also possible to specialize `datatype` instead of providing a\nnested `mpl_datatype` alias. So this definition of `cons` is equally\nvalid (and the other constructors could be defined analogously):\n\n```cpp\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons; // no nested mpl_datatype\n\nnamespace boost { namespace mpl11 {\n    template \u003ctypename Head, typename Tail\u003e\n    struct datatype\u003ccons\u003cHead, Tail\u003e\u003e {\n        using type = List;\n    };\n}}\n```\n\nBeing able to do this is paramount when adapting code over which we don't have\nthe control, but for simplicity we'll stick with the nested `mpl_datatype`\nwhenever possible. When unspecialized, `datatype\u003cT\u003e` simply returns\n`T::mpl_datatype` if that expression is a valid type name, and `Foreign`\notherwise. Hence, `Foreign` is the default datatype of everything.\n\n\u003e Note that `datatype` is a strict metafunction and that it does not obey the\n\u003e convention of taking boxed arguments. Breaking the convention is necessary\n\u003e to allow user-defined specializations.\n\n\n### Boxed data constructors\nWhile it is not mandatory, it is often a good idea to box data constructors\nsince it makes them usable as-is in lazy metafunctions. Let's rewrite the\nprevious data constructors that way:\n\n```cpp\ntemplate \u003ctypename ...Elements\u003e\nstruct list_impl {\n    using mpl_datatype = List;\n};\n\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons_impl {\n    using mpl_datatype = List;\n};\n\nstruct nil_impl { using mpl_datatype = List; };\n\n\ntemplate \u003ctypename ...Elements\u003e\nstruct list {\n    using type = list_impl\u003cElements...\u003e;\n};\n\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons {\n    using type = cons_impl\u003cHead, Tail\u003e;\n};\n\nstruct nil {\n    using type = nil_impl;\n};\n```\n\nThe downside is that we end up with twice the amount of code, half of which\nis complete boilerplate. Also, this approach causes twice as many templates\nto be instantiated each time we unbox a data constructor, which can hurt\ncompile-time performance. Fortunately, we can use self-referential boxing\nto make this better.\n\n```cpp\ntemplate \u003ctypename ...Elements\u003e\nstruct list {\n    using type = list;\n    using mpl_datatype = List;\n};\n\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons {\n    using type = cons;\n    using mpl_datatype = List;\n};\n\nstruct nil {\n    using type = nil;\n    using mpl_datatype = List;\n};\n```\n\nThat way, only one additional line of code is required per data constructor\nand we only instantiate one template when we unbox it. Indeed,\n`cons\u003c...\u003e::type` is just `cons\u003c...\u003e`, which is already instantiated.\n\nYou might wonder why I have even bothered with the inferior solution using\n`cons_impl` and friends in the first place, since the self-referential\nsolution is so obvious. This was to highlight the fact that boxed data\nconstructors do not _need_ to be self-referential; it is merely a convenient\nimplementation trick. This is a subtle difference between the MPL11 and the\n[mpllibs][] library collection, which I wanted to point out.\n\n\n### Laziness in data constructors\nThere is something rather important that we have left undefined when we\ncreated the `list` and `cons` data constructors: what do their arguments\nlook like?\n\n```cpp\ntemplate \u003ctypename ...Elements\u003e\nstruct list;\n\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct cons;\n```\n\nThere are two possible answers here, and both are valid. In the end, this is\nmainly a design choice. The first option is to require the arguments to be\nnormal (non-boxed) types. We could then use the constructors like so:\n\n```cpp\nusing x = list\u003cint, char, float\u003e;\nusing y = cons\u003cint, list\u003cchar, float\u003e\u003e;\nusing z = cons\u003cint, cons\u003cchar, cons\u003cfloat, nil\u003e\u003e\u003e;\n```\n\nThe second option is to require boxed arguments. We could then use the\nconstructors like so:\n\n```cpp\nusing x = list\u003cbox\u003cint\u003e, box\u003cchar\u003e, box\u003cfloat\u003e\u003e;\nusing y = cons\u003cbox\u003cint\u003e, list\u003cbox\u003cchar\u003e, box\u003cfloat\u003e\u003e\u003e;\nusing z = cons\u003cbox\u003cint\u003e, cons\u003cbox\u003cchar\u003e, cons\u003cbox\u003cfloat\u003e, nil\u003e\u003e\u003e;\n```\n\n\u003e Note that we do not need to box the second arguments to `cons` ourselves,\n\u003e because we have already made `list`, `cons` and `nil` boxed.\n\nThis is clearly less natural than the first solution. Still, for reasons\nthat will soon become clearer, the MPL11 `List` constructors use the second\nsolution, and so will we for the rest of this tutorial. To reduce the\nsyntactic noise, we will define aliases that will make our life easier:\n\n```cpp\ntemplate \u003ctypename ...Elements\u003e\nusing list_ = list\u003cbox\u003cElements\u003e...\u003e;\n\ntemplate \u003ctypename Head, typename Tail\u003e\nusing cons_ = cons\u003cbox\u003cHead\u003e, box\u003cTail\u003e\u003e;\n```\n\n\u003e Note that we would not need to box the second argument of `cons_` because we\n\u003e expect it to be a `List`, and all `List` constructors are already boxed. So\n\u003e `box\u003cTail\u003e` is really redundant, but we still do it here for the sake of\n\u003e clarity.\n\nWe will say that a data constructor taking unboxed arguments is __strict__,\nand that a data constructor taking boxed arguments is __lazy__. An interesting\nobservation is that some (but not all) constructors are also metafunctions.\nSpecifically, boxed constructors taking type template parameters are\nmetafunctions. Therefore, strict boxed constructors correspond to strict\nmetafunctions, and lazy boxed constructors correspond to lazy metafunctions!\n\n\n### Conversions\nThe MPL11 provides a way to convert values from one datatype to the other. The\nusefulness of this is clearest when implementing numeric datatypes, but we'll\nstick with `List` because we already have it. Let's suppose we want to convert\nvalues from a `List` to an `std::tuple` and vice-versa. First, we will need to\ndefine a datatype of which `std::tuple` can be a data constructor.\n\n```cpp\nstruct StdTuple;\n\nnamespace boost { namespace mpl11 {\n    template \u003ctypename ...T\u003e\n    struct datatype\u003cstd::tuple\u003cT...\u003e\u003e {\n        using type = StdTuple;\n    };\n}}\n```\n\nWe can now consider `std::tuple` as a data constructor for the `StdTuple`\ndatatype. Note that unlike the arguments to `list`, the arguments to\n`std::tuple` must be unboxed; this will be important for what follows.\nThe next step is to implement the conversion itself. This is done by\nspecializing the `cast` lifted metafunction for the involved datatypes.\n\n```cpp\nnamespace boost { namespace mpl11 {\n    template \u003c\u003e\n    struct cast\u003c/*from*/ List, /*to*/ StdTuple\u003e {\n        template \u003ctypename\u003e\n        struct apply;\n\n        template \u003ctypename ...Elements\u003e\n        struct apply\u003clist\u003cElements...\u003e\u003e {\n            using type = std::tuple\u003ctypename Elements::type...\u003e;\n        };\n\n        template \u003c\u003e\n        struct apply\u003cnil\u003e {\n            using type = std::tuple\u003c\u003e;\n        };\n\n        template \u003ctypename Head, typename Tail\u003e\n        struct apply\u003ccons\u003cHead, Tail\u003e\u003e {\n            using type = /* omitted for simplicity */;\n        };\n    };\n\n    template \u003c\u003e\n    struct cast\u003c/*from*/ StdTuple, /*to*/ List\u003e {\n        template \u003ctypename\u003e\n        struct apply;\n\n        template \u003ctypename ...Elements\u003e\n        struct apply\u003cstd::tuple\u003cElements...\u003e\u003e {\n            using type = list_\u003cElements...\u003e;\n        };\n    };\n}}\n```\n\nThere are a few things to note here. First, it is very important to provide a\nconversion for all the data constructors of a datatype. If, for instance, we\nhad forgotten to provide `apply\u003cnil\u003e`, we could only convert from the `list`\nand `cons` constructors. Second, we had to unbox the elements of the `list`\nwhen passing them to `std::tuple` because `std::tuple` expects unboxed types.\nSimilarly, we had to box the elements of the `std::tuple` when passing them to\n`list`. Third, the `cast` lifted metafunction is strict and it does not follow\nthe convention of taking boxed arguments, which makes it possible to pattern\nmatch data constructors. Here is how we could now convert between the two\ndatatypes:\n\n```cpp\nusing my_list = list_\u003cint, char, float\u003e;\nusing my_tuple = std::tuple\u003cint, char, float\u003e;\n\ncast\u003cList, StdTuple\u003e::apply\u003cmy_list\u003e::type; // == my_tuple\ncast\u003cStdTuple, List\u003e::apply\u003cmy_tuple\u003e::type; // == my_list\n```\n\nAlso note that casting from a datatype `T` to itself is a noop, so you don't\nhave to worry about that trivial case. The library also defines a handy\n`cast_to` lifted metafunction that reduces the syntactic noise of `cast`:\n\n```cpp\ncast_to\u003cStdTuple\u003e::apply\u003cmy_list\u003e::type; // == my_tuple\ncast_to\u003cList\u003e::apply\u003cmy_tuple\u003e::type; // == my_list\n```\n\n`cast_to` simply deduces the datatype to cast from by using that of its\nargument and then forwards to `cast`. `cast_to` is strict and does not\ntake boxed arguments.\n\n\u003e __TODO__: Give more details on the `Foreign` datatype.\n\n\n## Methods\nSo far, we have created the `List` datatype and a couple of constructors to\ncreate \"values\" of that type, but we still don't have a way to manipulate\nthose values in a useful way. Let's define a `head` metafunction that will\nreturn the first element of a `List`. We will stick to the convention of\ntaking boxed arguments.\n\n```cpp\ntemplate \u003ctypename List\u003e\nstruct head_impl;\n\ntemplate \u003ctypename Head, typename ...Tail\u003e\nstruct head_impl\u003clist\u003cHead, Tail...\u003e\u003e\n    : Head\n{ };\n\ntemplate \u003ctypename Head, typename Tail\u003e\nstruct head_impl\u003ccons\u003cHead, Tail\u003e\u003e\n    : Head\n{ };\n\n// head_impl\u003cnil\u003e is not defined since that's an error.\n\ntemplate \u003ctypename List\u003e\nstruct head\n    : head_impl\u003ctypename List::type\u003e\n{ };\n```\n\nFirst, we need to add a level of indirection (`head_impl`) because `head`\nreceives boxed arguments and we need to pattern match the constructors.\nSecond, note that `head` is a strict metafunction because its argument\nis always evaluated. Third, we inherit from `Head` in `head_impl` because\nthe `List` constructors are lazy and hence `Head` is boxed.\n\nIt is now possible to see why it was useful to make the `List` constructors\nlazy. Consider the following situation:\n\n```cpp\nusing refs = list\u003c\n    std::add_lvalue_reference\u003cint\u003e,\n    std::add_lvalue_reference\u003cvoid\u003e\n\u003e;\n\nhead\u003crefs\u003e::type; // == int\u0026\n```\n\nSince we can't form a reference to `void`, we will trigger a compile-time\nerror if we evaluate the `std::add_lvalue_reference\u003cvoid\u003e` thunk. However,\nsince we only ever use the value of the first element in the list, it would\nbe nice if we could only evaluate that element, right? Making `list` a lazy\nconstructor makes that possible. If, instead, we had decided to make `list`\nstrict, we would need to write:\n\n```cpp\nusing refs = list\u003c\n    std::add_lvalue_reference\u003cint\u003e::type,\n    std::add_lvalue_reference\u003cvoid\u003e::type\n\u003e;\n```\n\nwhich does not compile. The same reasoning is valid if the contents of the\nlist were the results of complicated computations. By making the constructor\nlazy, we would only need to evaluate those computation whose result is\nactually used. In the end, the reasons for writing lazy data constructors\nare similar to the reasons for writing lazy metafunctions.\n\nThe `head` metafunction we have so far is useful, but consider the following\ndatatype and lazy boxed constructor:\n\n```cpp\nstruct Vector;\n\ntemplate \u003ctypename ...Elements\u003e\nstruct vector {\n    struct type {\n        using mpl_datatype = Vector;\n    };\n};\n\ntemplate \u003ctypename Head, typename ...Tail\u003e\nstruct vector\u003cHead, Tail...\u003e {\n    struct type {\n        using head = Head;\n        using mpl_datatype = Vector;\n    };\n};\n```\n\nSince `Vector` is really some kind of `List`, it is only reasonable to expect\nthat we can invoke `head` on a `Vector` just like we do on a `List`. But how\nwould we go about implementing `head` for `Vector`? Assuming we can't modify\nthe implementation of `Vector`, the only way we have right now is to use\npartial specialization of `head_impl` on `Vector`'s constructor.\nUnfortunately, that constructor is `vector\u003c...\u003e::type`, not `vector\u003c...\u003e`.\nSince we can't partially specialize on a dependent type, we're out of luck.\nTo bypass this limitation, we will refine `head` so it uses the datatype of\nits argument.\n\n```cpp\ntemplate \u003ctypename Datatype\u003e\nstruct head_impl;\n\ntemplate \u003ctypename List\u003e\nstruct head\n    : head_impl\u003ctypename datatype\u003ctypename List::type\u003e::type\u003e::\n      template apply\u003ctypename List::type\u003e\n{ };\n```\n\nWe now consider `head_impl` as a lifted metafunction parameterized over the\ndatatype of its argument. Implementing `head` for `List` and `Vector` is now\na breeze.\n\n```cpp\ntemplate \u003c\u003e\nstruct head_impl\u003cList\u003e {\n    template \u003ctypename\u003e struct apply;\n\n    template \u003ctypename Head, typename ...Tail\u003e\n    struct apply\u003clist\u003cHead, Tail...\u003e\u003e\n        : Head\n    { };\n\n    template \u003ctypename Head, typename Tail\u003e\n    struct apply\u003ccons\u003cHead, Tail\u003e\u003e\n        : Head\n    { };\n};\n\ntemplate \u003c\u003e\nstruct head_impl\u003cVector\u003e {\n    template \u003ctypename v\u003e\n    struct apply\n        : v::head\n    { };\n};\n```\n\nIt is sometimes useful to exert a finer grained control over template\nspecializations than what we currently have. A common idiom is for the\nprimary template to provide an additional dummy parameter which can be\nSFINAE'd upon in partial specializations:\n\n```cpp\ntemplate \u003ctypename T, typename Enable = void\u003e\nstruct trait;\n\ntemplate \u003ctypename T\u003e\nstruct trait\u003cT, std::enable_if_t\u003cstd::is_trivial\u003cT\u003e::value\u003e\u003e {\n    // ...\n};\n```\n\nThis enables the specialization to depend on an arbitrary compile-time boolean\nexpression (in fact on the syntactic validity of an arbitrary expression).\nNote that all partial specializations using the enabler must have mutually\nexclusive conditions or the specialization will be ambiguous; this can be\ntricky at times. A variant of this trick is to use a default type of `true_`\ninstead of `void` for the dummy template parameter. That makes it possible to\nleave the `std::enable_if_t` part for most use cases:\n\n```cpp\ntemplate \u003ctypename T, typename Enable = true_\u003e\nstruct trait;\n\ntemplate \u003ctypename T\u003e\nstruct trait\u003cT, bool_\u003cstd::is_trivial\u003cT\u003e::value\u003e\u003e {\n    // ...\n};\n```\n\n\u003e Note that we used `bool_\u003c...\u003e` instead of `std::is_trivial\u003cT\u003e::type` because\n\u003e the latter is `std::true_type`, which is not necessarily the same as `true_`.\n\u003e\n\u003e Also, we don't use a straight `bool` for the enabler because partial\n\u003e specializations cannot have dependent non-type template arguments.\n\nSince this functionality can really be useful, it might be a good idea to\nsupport it in the `head_impl` lifted metafunction. Fortunately, that only\nrequires changing the `head_impl` forward declaration to:\n\n```cpp\ntemplate \u003ctypename Datatype, typename = true_\u003e\nstruct head_impl;\n```\n\n\u003e __TODO__: Provide a use case where this is useful.\n\nIn this section, we went through the process of designing a simple yet\npowerful way of dispatching metafunctions. The subset of metafunctions\nusing this dispatching technique are called __methods__ in the MPL11.\n\n\u003e __TODO__: Tackle binary operators and mixed-datatype dispatch.\n\n\n### Typeclasses\nTypeclasses come from the observation that some methods are naturally related\nto each other. For example, take the `head`, `tail` and `is_empty` methods.\nWhen implementing any of these three methods, it is probable that the other\ntwo should also be implemented. Hence, it would be logical to group them in\nsome way; that is the job of typeclasses. However, typeclasses are much more\nthan mere method bundles. They provide a clean way of specifying and extending\nthe interface of a datatype through a process called typeclass instantiation.\n\nLet's make a typeclass out of the `head`, `tail` and `is_empty` methods.\nDatatypes supporting all three methods look somewhat like `List`s; hence\nwe will call the typeclass `Iterable`. We start by grouping the `*_impl`\nlifted metafunctions of the methods together under the `Iterable` banner.\nIn the following code snippets, the `tail` and `is_empty` methods will be\nomitted when illustrating `head` suffices.\n\n```cpp\nstruct Iterable {\n    template \u003ctypename Datatype, typename = true_\u003e\n    struct head_impl;\n\n    // ...\n};\n\ntemplate \u003ctypename Iter\u003e\nstruct head\n    : Iterable::head_impl\u003ctypename datatype\u003ctypename Iter::type\u003e::type\u003e::\n      template apply\u003ctypename Iter::type\u003e\n{ };\n\n// ...\n```\n\nTo implement the methods for `List`, we now have to write:\n\n```cpp\ntemplate \u003c\u003e\nstruct Iterable::head_impl\u003cList\u003e {\n    template \u003ctypename the_list\u003e\n    struct apply {\n        // ...\n    };\n};\n```\n\nSoon enough, we notice that we can regroup the datatype parametrization on\n`Iterable` instead of leaving it on each nested lifted metafunction.\n\n```cpp\ntemplate \u003ctypename Datatype, typename = true_\u003e\nstruct Iterable {\n    struct head_impl;\n\n    // ...\n};\n\ntemplate \u003ctypename Iter\u003e\nstruct head\n    : Iterable\u003ctypename datatype\u003ctypename Iter::type\u003e::type\u003e::\n      head_impl::template apply\u003ctypename Iter::type\u003e\n{ };\n\n// ...\n```\n\nThe next logical step is to prune the superfluous indirection through the\n`*_impl` lifted metafunctions and to simply make them metafunctions.\n\n```cpp\ntemplate \u003ctypename Datatype, typename = true_\u003e\nstruct Iterable {\n    template \u003ctypename Iter\u003e\n    struct head_impl;\n\n    // ...\n};\n\ntemplate \u003ctypename Iter\u003e\nstruct head\n    : Iterable\u003ctypename datatype\u003ctypename Iter::type\u003e::type\u003e::\n      template head_impl\u003ctypename Iter::type\u003e\n{ };\n\n// ...\n```\n\nSince it might be useful to query whether a datatype supports the operations\nof `Iterable`, we would like to have a boolean metafunction that does just\nthat. Fortunately, we can use the `Iterable` for this task with a small\nmodification.\n\n```cpp\ntemplate \u003ctypename Datatype, typename = true_\u003e\nstruct Iterable : false_ {\n    // ...\n};\n```\n\nBy default, `Iterable` is therefore also a boolean metafunction returning\n`false`, meaning that arbitrary datatypes don't implement the `head`, `tail`\nand `is_empty` metafunctions. In its current form, the `Iterable` template is\ncalled a __typeclass__, and metafunctions like `head` following this\ndispatching pattern through a typeclass are called __typeclass methods__.\nIn order to implement `head` and friends, one would now write\n\n```cpp\ntemplate \u003c\u003e\nstruct Iterable\u003cList\u003e : true_ {\n    template \u003ctypename the_list\u003e\n    struct head_impl {\n        // ...\n    };\n\n    // ...\n};\n\nstatic_assert(Iterable\u003cList\u003e{}, \"List is an Iterable!\");\n```\n\nThe three methods `Iterable` contains so far are very basic; for any given\ndatatype, it is not possible to provide a suitable default implementation.\nHowever, there are other metafunctions that can be implemented in terms of\nthese three basic blocks. For example, consider the `last` metafunction that\nreturns the last element of an `Iterable`. A possible implementation would be:\n\n```cpp\ntemplate \u003ctypename iter\u003e\nstruct last\n    : if_\u003cis_empty\u003ctail\u003citer\u003e\u003e,\n        head\u003citer\u003e,\n        last\u003ctail\u003citer\u003e\u003e\n    \u003e\n{ };\n```\n\nWhile we could provide this metafunction as-is, some datatypes might be able\nto provide a more efficient implementation. Therefore, we would like to make\nit a method, but one that can be defaulted to the above.\n\n\u003e Note that method dispatching incurs some compile-time overhead; hence there\n\u003e is a tradeoff between using (typeclass) methods and regular metafunctions.\n\u003e The rule of thumb is that if a method is likely to never be specialized\n\u003e (i.e. the default implementation is almost always the best), then it should\n\u003e probably be a regular metafunction.\n\nIt turns out that providing a default implementation can be done easily using\ntypeclasses and a little convention. First, we make `last` a normal typeclass\nmethod.\n\n```cpp\ntemplate \u003ctypename Iter\u003e\nstruct last\n    : Iterable\u003ctypename datatype\u003ctypename Iter::type\u003e::type\u003e::\n      template last_impl\u003ctypename Iter::type\u003e\n{ };\n```\n\nThen, we require specializations of `Iterable` to inherit some special type\nas follows:\n\n```cpp\ntemplate \u003c\u003e\nstruct Iterable\u003cList\u003e : instantiate\u003cIterable\u003e::with\u003cList\u003e {\n    // ...\n};\n```\n\nHere, `instantiate\u003c...\u003e::with\u003c...\u003e` is `true_` by default. Hence, it only\ntakes care of making `Iterable` a true-valued boolean metafunction, which we\ndid by ourselves previously. However, `instantiate` may be specialized by\ntypeclass designers in such a way that the member template `with` also\ncontains default methods. In our case, we would provide a `last_impl`\nmetafunction corresponding to the default implementation of `last` shown\nabove. This way, if a datatype does not implement the `last` method, our\ndefault implementation will be used.\n\n```cpp\nnamespace boost { namespace mpl11 {\n    template \u003c\u003e\n    struct instantiate\u003cIterable\u003e {\n        template \u003ctypename Datatype\u003e\n        struct with : true_ {\n            template \u003ctypename Iter\u003e\n            struct last_impl {\n                // default implementation\n            };\n        };\n    };\n}}\n```\n\nThis technique provides a lot more flexibility. One notable improvement is the\nability to add new methods to `Iterable` without breaking existing client code,\nprovided the new methods have a default implementation. Hence, in the MPL11,\nall typeclass specializations are required to use this technique, regardless\nof whether they actually need defaulted methods.\n\n\u003e You might wonder why we use `instantiate\u003cTypeclass\u003e::with\u003cDatatypes...\u003e`\n\u003e instead of just using `instantiate\u003cTypeclass\u003e`. This is because some\n\u003e typeclasses need to know the datatype(s) they operate on to provide\n\u003e meaningful defaults. Also, we don't use `instantiate\u003cTypeclass, Datatypes...\u003e`\n\u003e because that would make defaulted typeclass parameters hard to handle.\n\nA typeclass specialization using the technique we just saw is called a\n__typeclass instantiation__. When a typeclass instantiation exists for\na typeclass `T` and a datatype `D`, we say that `D` is an __instance__ of\n`T`. Equivalently, we say that `D` __instantiates__ `T`, or sometimes that\n`D` __is a__ `T`. The set of definitions that _must_ be provided for a\ntypeclass to be complete is called the __minimal complete definition__ of\nthe typeclass. The minimal complete definition is typically the set of methods\nwithout a default implementation, but it must be documented for each typeclass.\n\n\u003e The term _typeclass instantiation_ is borrowed from Haskell and should not be\n\u003e mistaken with _template instantiation_ even though they share similarities,\n\u003e especially in the MPL11.\n\n\u003c!--  --\u003e\n\n\u003e __TODO__\n\u003e - Tackle mixed-datatype typeclass-method dispatch\n\n\n### Rewrite rules\n__TODO__\n\n\n## Acknowledgements\nThe development of this library drew inspiration from a couple of projects with\ndifferent levels of involvement in template metaprogramming. I would like to\nthank the people involved in these projects for their work, without which this\nlibrary wouldn't be the same. The most notable sources of inspiration and\nenlightenment were:\n\n- The [Haskell][] programming language\n- The original [Boost.MPL][]\n- The [mpllibs][] library\n\n\n## Rationales\nThis section contains rationales for some design decisions of the library. In\nits early development, the library was rewritten several times because\nfundamental aspects of it needed to be changed. Hence, only the rationales\npertaining to the current design are kept here. If you have a question about\na design decision that is not explained here, please contact the creator of\nthe library (Louis Dionne).\n\n### Why are iterators not used in the library?\nThe following points led to their removal:\n- Lazy views were hard to implement because they required creating new\n  iterators, which is a pain. Using a different abstraction for sequences\n  made it much easier.\n- Iterators being hard to implement and non-composable is a known problem,\n  which is addressed e.g. by the Boost.Range library or in this\n  [paper][on-iteration] by Andrei Alexandrescu.\n- There is no performance gain to be achieved by using iterators. In fact, it\n  often makes straightforward implementations more complicated, which can hide\n  possible optimizations.\n- Implementing infinite ranges using iterators is hacky at best.\n\n### Why isn't `apply` a method?\nThere are two main reasons for this. First, if `apply` were a method, one would\nneed to make every lifted metafunction an instance of the typeclass defining\n`apply`. Since lifted metafunctions are very common, that would be very\ncumbersome. Second, making `apply` a method requires using the usual method\ndispatching mechanism, which adds some overhead.\n\n### Why aren't `and_`, `or_` and `not_` methods?\nIn some previous design of the library, these were methods. However, allowing\n`and_` and `or_` to be non-strict required special casing these methods. Since\nI could not find any use case, I decided to make them normal metafunctions.\n\n### Why aren't `*_t` versions of metafunctions provided like in C++1y?\nSwitching the evaluation burden from the caller to the callee makes this useless\nin most cases.\n\n### Why are MPL-style non-template nullary metafunctions not allowed?\nIt introduces a special case in the definition of metafunction that prevents us\nfrom using `f::apply\u003c\u003e` to invoke a nullary lifted metafunction. We have to use\n`apply\u003cf\u003e`, which will then use either `f::apply\u003c\u003e` or `f::apply`. This adds a\ntemplate instantiation and an overload resolution to each lifted metafunction\ninvocation, which significantly slows down compilation. Considering nullary\nmetafunctions are of limited use anyway (why would you want a function without\narguments in a purely functional setting?), this is not worth the trouble. Also,\nnote that MPL-style nullary non-template metafunctions fit in the definition of\na boxed type, so they're not completely forgotten.\n\n\n## Todo list\n- [ ] What should we do for default typeclass methods?\n      1. We reuse the \"official\" method and we rebox the arguments.\n        ```cpp\n        template \u003ctypename x, typename y\u003e\n        using equal_impl = not_\u003cnot_equal\u003cbox\u003cx\u003e, box\u003cy\u003e\u003e\u003e;\n        ```\n\n      2. We create an \"official\" unboxed method and we use that.\n        ```cpp\n        template \u003ctypename x, typename y\u003e\n        using equal_impl = not_\u003cnot_equal_\u003cx, y\u003e\u003e;\n        ```\n        where `not_equal_` is a non-boxed version of `not_equal`.\n\n      3. We directly forward to the implementation of the method in the\n         typeclass.\n        ```cpp\n        template \u003ctypename x, typename y\u003e\n        using equal_impl = not_\u003cComparable\u003cLeft, Right\u003e::not_equal_impl\u003cx, y\u003e\u003e;\n        ```\n- [ ] Implement cross-type typeclasses.\n- [ ] Implement associative data structures.\n- [ ] Implement a small DSL to implement inline lifted metafunctions (like\n      Boost.MPL's lambda). Consider let expressions. Using the Boost.MPL lingo,\n      such a DSL should:\n      - Allow leaving placeholders as-is inside a lambda, if this is desirable.\n      - Allow performing placeholder substitution in a lambda without actually\n      evaluating the expression, if this is desirable.\n      - Allow \"variadic placeholders\", i.e. placeholders expanding to several\n      types. One pitfall of this is using such a placeholder with a\n      metafunction that is not variadic:\n\n        ```cpp\n        template \u003ctypename, typename\u003e\n        struct f;\n        using F = lambda\u003cf\u003c_args\u003e\u003e; // error here, f is not unary\n        using Result = F::apply\u003cint, char\u003e::type;\n        ```\n      This fails because `f` requires 2 arguments.\n- [ ] Consider allowing types to be printed somehow. The idea is to have\n      something like a `Show` typeclass that allows types to be pretty-printed\n      for debugging purposes.\n- [ ] Think about a convention or a system to customize some metafunction calls.\n      Something neat would be to have a way of passing a custom predicate when\n      comparing sequences; that would make `equal` as powerful as the `equal`\n      algorithm from the Boost.MPL. Maybe we can achieve the same effect in\n      another way.\n- [ ] Consider having a wrapper that allows treating template specializations\n      as data. Something like sequence operations on template specializations\n      and/or tree operations.\n- [ ] Consider adding `while_` and `until` metafunctions.\n- [ ] Consider ditching `Foreign` and making the default datatype the data\n      constructor itself.\n- [ ] Consider adding `Either`.\n- [ ] Right now, we must include `boost/mpl11/core.hpp` to get the\n      `instantiate\u003c\u003e` template in client code. Maybe typeclass headers\n      should take care of it. Or maybe `boost/mpl11/core.hpp` should\n      never have to be included by clients altogether?\n- [ ] Add interoperability with the Boost.MPL, Boost.Fusion and components\n      in the `std` namespace.\n- [ ] Use `constexpr` to perform numeric computations on homogeneous sequences\n      of integral constants.\n- [ ] Consider providing data constructors taking unboxed types for convenience.\n- [ ] Consider making `int_\u003c\u003e` a simple boxed `int` without a value.\n- [ ] Write a rationale for why we don't have parameterized datatypes.\n      Or is this possible/useful?\n- [ ] Make bool.hpp lighter. In particular, it should probably not depend\n      on integer.\n- [ ] Design a StaticConstant concept?\n- [ ] In the tutorial, when we specialize lifted metafunctions inside the\n      `boost::mpl11` namespace, we don't make them boxed. This makes sense\n      because they are lifted metafunctions, not boxed lifted metafunctions.\n      What should we do? Should we\n      1. Make the specializations boxed\n      2. Do not take for granted that they are boxed when we use them in the\n         library and box them redundantly, which is correct but suboptimal.\n      3. Explicitly state that nothing may be specialized inside the\n         `boost::mpl11` namespace unless specified otherwise. Then,\n         specify what can be specialized on a per-component basis and\n         then we apply (2) only to the components that might not be boxed.\n- [ ] Consider having a public data constructor for `Foreign`, which would\n      simply preserve type identity. Also; might consider changing the name\n      of `Foreign`.\n- [ ] Consider regrouping the typeclass instantiations of a datatype in the\n      datatype itself. This was done in a previous version, but it might have\n      some advantages.\n- [ ] Consider providing automatic currying for metafunctions.\n- [ ] By making some std algorithms constexpr and providing a couple of\n      containers with constexpr iterators, would we have constexpr for free\n      almost everywhere?\n- [ ] Consider making `bool_` a lifted metafunction that behaves like `if_`.\n- [ ] Provide a better syntax for casting. Consider `cast\u003cDatatype(expr)\u003e`.\n- [ ] Seriously consider making datatypes lifted metafunctions.\n- [ ] Consider prototype-based objects?\n\n\n\u003c!-- Links --\u003e\n[Boost.MPL]: http://www.boost.org/doc/libs/1_55_0b1/libs/mpl/doc/index.html\n[call-by-value]: http://en.wikipedia.org/wiki/Call_by_value\n[Cmake]: http://www.cmake.org\n[doxygen-doc]: http://ldionne.github.io/mpl11\n[hana_github]: http://github.com/ldionne/hana\n[haskell-denot-semantics]: http://en.wikibooks.org/wiki/Haskell/Denotational_semantics\n[Haskell]: http://www.haskell.org\n[lazy]: http://en.wikipedia.org/wiki/Lazy_evaluation\n[mpllibs]: http://github.com/sabel83/mpllibs\n[on-iteration]: http://www.informit.com/articles/article.aspx?p=1407357\n[wiki-tmp]: http://en.wikipedia.org/wiki/Template_metaprogramming\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fldionne%2Fmpl11","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fldionne%2Fmpl11","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fldionne%2Fmpl11/lists"}