Boost logo

Boost :

Subject: Re: [boost] [GSoC, MPL11] Community probe
From: Louis Dionne (ldionne.2_at_[hidden])
Date: 2014-04-29 17:40:02


Gonzalo Brito Gadeschi <g.brito <at> aia.rwth-aachen.de> writes:

> I have a question: the proposal and library are called MPL11.

That is true, but I'm starting to realize that it's a very bad name. The
project started about two years ago, when C++14 was still out of my sight.
Be reassured that I always consider the latest version of the language, not
only C++11.

> In my experience, relaxed constexpr allows for beautiful metaprogramming
> with respect to C++11, in particular when combined with Boost.Fusion, and I
> think that it is really a game changer with respect to C++11 constexpr,
> since it allows not only "functional" metaprogramming but also "imperative"
> metaprogramming, significantly lowering the learning curve of
> metaprogramming for C++ programmers.

Could you please expand on the nature of metaprogramming you have been doing
with constexpr? Are you talking about manipulating values of a literal type,
or about "pure type" computations? See below for more on that.

> Have you consider the influence of relaxed constexpr (C++14) in your
> library?
>
> Could it simplify the design/implementation/usage of the MPL?

I did consider the impact of C++14 on the design of the library, and I
still am. At this point, my conclusion is that we must define what we
mean by a "template metaprogramming library".

I differentiate between two main kinds of computations that can be done at
compile-time. The first is manipulating "pure types" with metafunctions
(e.g. type traits):

    using void_pointer = std::add_pointer_t<void>;
    using pointers = mpl::transform<
        mpl::list<int, char, void, my_own_type>,
        mpl::quote<std::add_pointer>
>::type;

The above example is completely artificial but you get the point. The second
kind of computation is manipulating values of a literal type at compile-time.

    using three = mpl::plus<mpl::int_<1>, mpl::int_<2>>::type;

The MPL wraps these values into types so it can treat computations on those
as computations of the first kind, but another library could perhaps handle
them differently (probably using constexpr).

    constexpr int three = plus(1, 2);

It is easy to see how constexpr (and relaxed constexpr) can make the second
kind of computation easier to express, since that is exactly its purpose.
However, it is much less clear how constexpr helps us with computations of
the first kind. And by that I really mean that using constexpr in some way
to perform those computations might be more cumbersome and less efficient
than good old metafunctions.

As for using constexpr to express computations on literal values, another
question arises. Should there be a general library for handling those at
compile-time, or should it be the responsibility of a well written domain-
specific library to provide means to perform domain-specific computations
at compile-time whenever possible?

For example, should the MPL11 provide constexpr math functions, or should
the std:: math functions be constexpr whenever possible? Another example
is std::array. While the MPL11 could provide a constexpr container for
homogeneous values of a literal type, simply changing the `begin` and
`end` of `std::array` to be constexpr would make it possible to iterate
on the array at compile-time.

    template <typename T, std::size_t n>
    constexpr T sum(std::array<T, n> array) {
        T s{0};
        for (T i: array) // awesome
            s += i;
        return s;
    }

    constexpr std::array<int, 5> array{{1, 2, 3, 4, 5}};
    static_assert(sum(array) == 15, "");

Unfortunately, I don't think this is happening in C++14, but I could be
mistaken. Still, you certainly understand the implications.

So a valid question that must be answered before I/we can come up with
a "final" version of the library that can be proposed to Boost (or for
standardization) is:

    "What is the purpose of a TMP library?"

Once that is well defined, we won't be shooting at a moving target anymore.
Right now, I have avoided these questions as much as possible by focusing on
computations of the first kind. For those computations, my research so far
shows that constexpr is unlikely to be of any help. If someone can come up
with counter-examples or ideas that seem to refute this, _please_ let me know
and I'll even buy you a beer in Aspen. This is _very_ important; it's central
to my current work.

> Would a rewrite of MPL11 be necessary afterwards (MPL14)?

If constexpr turns out to be a game changer for computations of the first
kind, then I suspect a large part of the current MPL11 would have to be
rewritten. Of course, I tried to prevent this from happening by going slowly
and looking at all the possibilities, but these things happen and it's part
of the game.

As for computations of the second kind, not _much_ work (comparatively) has
been done on them because I knew it was a can of worms. So even drastic
changes would not kill the library as it stands.

Finally, if any of this does not make sense to someone, please let me know
(on this list or privately) so I can explain further and correct any
fallacious reasoning on my part.

I hope this answers your questions; sorry for the long-winded answer
but I think it can be informative for others too.

Regards,
Louis


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk