Subject: Re: [boost] [review][mp11] Formal review of Mp11
From: Joaquin M LÃ³pez MuÃ±oz (joaquinlopezmunoz_at_[hidden])
Date: 2017-07-16 22:22:09
This is my review of Mp11. As I see it, an important use niche for this
library is to
allow for phasing out of Boost.MPL in C++11 compilers, so my review is
heavily biased by
To get acquainted with the lib, I made the little experiment of porting
from Boost.MPL to Mp11 , results can be seen at:
The process was relatively straightforward, 9x% of it was boilerplate
substitution of the
form s/[typename] mpl::xx<...>::type/mp11::mp_xx<...>. As for the rest,
no serious problem
was found. Compile times dropped slightly, maybe around 5-10%, but I
Mp11 makes the very sensible choice of coding metafunctions/type lists
class/alias templates. From this principle everything else follows quite
naturally. I also
commend dispensing with Boost.MPL iterators and using indexes instead.
1.1 I really don't like the mp_ prefix. I understand this is meant to
minimize clashes when
using namespace::mp11, but the same purpose can be served by simply
using namespace mp=boost::mp11. Having to add this pesky mp_ thing
always got in the
way of seamless porting, for no real benefit. To add more confusion,
(those in integer_sequence.hpp and tuple.hpp) don't have the prefix.
1.2 Why are quoted metafunctions codified with a fn member rather than
apply? Why call it quoted metafunctions rather than metafunction
classes, as Boost.MPL
1.3 I find that these metafunctions are missing/misplaced:
at/at_c (should be in list.hpp)
insert/insert_c/erase/erase_c (should be in list.hpp)
clear (should be in list.hpp)
1.4 Tuple operations are named differently from their C++14/17
"avoid ambiguities when both are visible or in unqualified calls". Yet,
this policy is not
followed in integer_sequence.hpp. I'd rather go the latter way.
1.5 Treatment of sets and maps is very dissimilar. Why mp_map_find but no
mp_set_find? Why mp_set_push_(back|front) but no mp_map_push_(back|front)?
Why mp_map_erase but no mp_set_erase? I think both interfaces should
same functions, except possibly mp_map_(replace|update).
1.5.1 I think that, for consistency, mp_map_find should return an index
(like mp_find) rather than the element or void.
1.6 Boost.MPL sequences simulate variadic behavior by having
type parameters. As a consequence, the following is somehow unexpected:
std::cout<<mp_size<boost::mpl::vector<int,char>>::value<<"\n"; //prints 20
Porting from / coexisting with Boost.MPL would be greatly aided by some
function to convert Boost.MPL sequences to Mp11 lists:
template<template<typename...> class M,typename... T>
using mp_mpl_sequence=typename mp_mpl_sequence_impl<MplSequence>::type;
mp_mpl_sequence<boost::mpl::vector<int,char>>>::value<<"\n"; // prints 2
1.7 mp_eval[_xx] functions should accept metafunctions in both their
true and false
branches. As it stands now, we'd have to write stuff like
to emulate (the as of yet non-existent)
The current behavior would be served by the new interface with little
I have to say I don't know how to apply this new behavior to mp_eval_if_q;
thinking out loud, we'd need something like
which doesn't look too pretty. A more exotic alternative could be
1.7.1 Why there's no eval_if_q_c (or eval_if_c_q?)
I had just a cursory look at the code, but everything seems clean and
straightforward. I like the fact that C++14/17 features are taken
advantage of when
available (e.g. variadic fold expressions). There are many lines wider
chars, but I think this is OK with current Boost guidelines.
Testing seems pretty exhaustive. I find it surprising that there's so much
boilerplate code repetition in the testing code --I'd have expected Mp11
be used to generate extensive test cases automatically.
This is IMHO the weakest part of this submission. I have concerns with
tutorial and the reference.
With template metaprogramming, one has to ask whether a tutorial for a
metaprogamming lib should be oriented towards explaining *metaprogramming*
or rather the particular design of the library. Mp11 documentation seems to
try both ways, and does not excel in either of them.
3.1.1 Examples are heavy handed and do not focus on why Mp11 is useful
discussion goes into the particular difficulties of the use cases
studied. I consider
myself a reasonably advanced metaprogrammer and found it difficult (and,
useless) to follow the exposition. For a newbie, the examples are just
a seasoned metaprogrammer wanting to learn Mp11, she's better off
definitions section only and then jumping into the reference. I suggest
taking a look
at Brigand tutorials, which are excellent at explaining the lib to
metaprogrammers in a step-by-step fashion. I think the key is Brigand
don't try to tackle industry-grade metaprogramming problems: they just
the reader along toy use cases, and that's really enough.
3.1.2 The definitions section, by contrast, is too terse and at points
vague to the
verge of incorrection:
- It is not "template class" but "class template".
- It is not made clear whether a list is a class/alias template (say,
rather an instantiation of this template (mp_list<int,char>). Same
metafunctions. The confusion extends to the reference, where class
their instantiations are named the same, for instance:
template<class L> using mp_reverse = /*...*/;
mp_reverse<L<T1, T2, â¦â, Tn>> is L<Tn, â¦â, T2, T1>.
- The above is not a legal subtlety: as it stands, the definition for
make sense, as it implies that a set is a *class template* that somehow
enforces unicity of template type parameters. Same goes for maps.
- All in all, seems like the author's intention is to define lists
(and sets and maps)
as *template class instantiations*: if this is the case then it has
to be explained
how two different lists (say, the result of pushing back a type to a
list) are connected
through their common class template.
- By contrast, seems like the intention is to define a metafunction as a
class/alias template rather than its instantiations (e.g. mp_size is
but mp_size<my_list> is not). If this is the case, then the assertion
"Another distinguishing feature of this approach is that lists
(L<Tâ¦â>) have the
same form as metafunctions (F<Tâ¦â>) and can therefore be used as such."
- There's a latent concept that goes undocumented, namely lists resulting
from the instantiation of a non-variadic class/alias template (e.g.
Mp11 metafunctions are not applicable to them (e.g. mp_push_back),
is not clearly documented.
To be clear, I'm not advocating mathematical rigor, but the current
confusing at best and can impede understanding at worst.
In general, the reference is too terse and overlooks important details.
3.2.1 A "Requires" clause should be added to many entries. For example,
it is not clear what happens with mp_at_c<L, I> when I is out of bounds
(it does not compile). Another example: mp_pop_front<std::pair<int,bool>>
does not compile because std::pair<int,bool> is not a "variadic sequence"
(missing concept here).
3.2.2 A complexity section should be added, where complexity is number of
of template instantiations. For instance, I don't know how costly set
As already suggested in another review, links to metaben.ch could be added.
4 WHY ANOTHER METAPROGRAMMING LIBRARY?
The landscape of C++ metaprogramming libs is quite populated. These libs
can be classified into (to follow metaben.ch's terminology) heterogeneous
(Boost.Fusion, Boost.Hana) and pure-type (Boost.MPL, Mp11, Brigand, Metal,
Kvasir). To be fair, we're dealing here with acceptance of a library
so we should only be really concerned about intra-Boost clashes, which
us with Boost.Fusion, Boost.Hana, Boost.MPL and Mp11. In my opinion,
heterogeneous and pure-type libs have different scopes and entry barriers:
for the kind of intra-lib scaffolding I find myself doing, I'd rather go
a pure-type metaprogramming lib before buying the complexities of
In this respect, a replacement for old and clunky Boost.MPL is most welcome,
and this is the place that Mp11 can occupy.
This said, we can also look out to the wider world and recognize that
Brigand have the very same design philosophy and come up with solutions
that are exactly interchangeable. It would be great if we could find a
efforts behind Mp11 and Brigand could be coordinated to come up with
something bigger that could serve as Boost's pure-type metaprogramming
as well as a non-Boost lib. To be honest, I don't have a clue how this
done, or whether there's willingness to collaborate among Mp11's and
5 ANSWERS TO REVIEW QUESTIONS
* Should Mp11 be accepted into Boost? Please state all conditions for
My vote is for CONDITIONAL ACCEPTANCE dependent upon proper addressing of,
mp_list<_1_1, _1_2, _1_4, _1_5, _1_7, _3_1_2, _3_2_1>
Of course I'd like all points of my review to be discussed, but I feel
only those listed
above are important enough to hold acceptance.
* What is your evaluation of the design?
* What is your evaluation of the implementation?
* What is your evaluation of the documentation?
* What is your evaluation of the potential usefulness of the library?
All addressed above, hopefully.
* Did you try to use the library? With what compiler? Did you have any
Yes. VS 2015. No problems.
* How much effort did you put into your evaluation? A glance? A quick
5-6 hours for the porting exercise, 4-5 hours for the review.
* Are you knowledgeable about the problem domain?
I've been metaprogramming for 14 years.
Thanks to Peter Dimov for his submission of Mp11 and for being such an
contributor to Boost during so many years.
JoaquÃn M LÃ³pez MuÃ±oz
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk