"Simple C++11 metaprogramming"

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
56 messages Options
123
Reply | Threaded
Open this post in threaded view
|

"Simple C++11 metaprogramming"

Peter Dimov-2
I've recently made the mistake to reread Eric Niebler's excellent "Tiny
Metaprogramming Library" article

http://ericniebler.com/2014/11/13/tiny-metaprogramming-library/

which of course prompted me to try to experiment with my own tiny
metaprogramming library and to see how I'd go about implementing tuple_cat
(a challenge Eric gives.)

Ordinarily, any such experiments of mine leave no trace once I abandon them
and move on, but this time I decided to at least write an article about the
result, so here it is, with the hope someone might find it useful. :-)

http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html 


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

charleyb123 .
Peter Dimov <[hidden email]> sayeth:

> I've recently made the mistake to reread Eric Niebler's excellent "Tiny
> Metaprogramming Library" article
>
> http://ericniebler.com/2014/11/13/tiny-metaprogramming-library/
>
> which of course prompted me to try to experiment with my own tiny
> metaprogramming library and to see how I'd go about implementing tuple_cat
> (a challenge Eric gives.)
>
> Ordinarily, any such experiments of mine leave no trace once I abandon
> them and move on, but this time I decided to at least write an article
> about the result, so here it is, with the hope someone might find it
> useful. :-)
>
> http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>

Very nice.  Very clean and impressive post.

I particularly liked these two assertions:

(a) mp_size to compute type-list length is a truly generic primitive which
is, "...so nice that [you'd] argue that all our metaprogramming primitives
ought to have this property."

(b) "Lack-of-higher-order-metaprogramming", suggesting that in C++11 and
beyond, we largely should not need metafunctions such as compose, bind, or
a lambda library.

Very interesting.  I find your argument compelling.

--charley

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Peter Dimov-2
charleyb123 . wrote:

> > http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>
>
> Very nice.  Very clean and impressive post.

Thank you. The speed at which you were able to read all of it is certainly
impressive in its own right.

> I particularly liked these two assertions:
>
> (a) mp_size to compute type-list length is a truly generic primitive which
> is, "...so nice that [you'd] argue that all our metaprogramming primitives
> ought to have this property."
>
> (b) "Lack-of-higher-order-metaprogramming", suggesting that in C++11 and
> beyond, we largely should not need metafunctions such as compose, bind, or
> a lambda library.

The only problem with (b) is that you can't define a template alias inside a
function, which I myself found more than a bit annoying. Lambda functions
a-la Hana have a distinct advantage here - they can be defined inside
functions.

Still. :-)


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Michael Caisse-3
In reply to this post by Peter Dimov-2
On 05/30/2015 09:26 AM, Peter Dimov wrote:

> I've recently made the mistake to reread Eric Niebler's excellent "Tiny
> Metaprogramming Library" article
>
> http://ericniebler.com/2014/11/13/tiny-metaprogramming-library/
>
> which of course prompted me to try to experiment with my own tiny
> metaprogramming library and to see how I'd go about implementing
> tuple_cat (a challenge Eric gives.)
>
> Ordinarily, any such experiments of mine leave no trace once I abandon
> them and move on, but this time I decided to at least write an article
> about the result, so here it is, with the hope someone might find it
> useful. :-)
>
> http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>

Excellent article Peter! It builds nicely from one concept to the next.

Within Spirit X3 we have been discussing lightweight metaprogramming in
the world of C++14. You have articulated very well what we are beginning
to discover - "I posit that such higher order metaprogramming is, in the
majority of cases, not necessary in C++11."  This thought intrigues me
and I'm excited to see how far we can take it in libraries such as
Spirit X3 and boostache.

Thank you for taking the time to put the article together and share it
with the community.

Take care -
michael

--
Michael Caisse
ciere consulting
ciere.com

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

charleyb123 .
In reply to this post by Peter Dimov-2
>
> charleyb123 . wrote:
>
>  > http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>>
>>
>> Very nice.  Very clean and impressive post.
>
>
Peter respondeth:

> Thank you. <snip, read-it-fast>


I happened to be looking at the screen when you posted, and opened the
link.  Still, I think it's greatly an attribute of the (very) high quality
of your post.  This was my "clean" reference:  Your post is very well
written, very well organized, and you express very clear assertions with
supporting rationale and example(s).  (Works for me, anyway.  ;-))

Bravo -- I'm sure it took you a LONG time to write.  There's a lot there,
and you clearly needed to experiment with the compiler quite-a-bit to
feel-your-way-through.

Greatly to your credit, I think this an especially timely topic.  I've been
thinking about similar things for a while, but not with the clarity and
understanding that you expressed.  Your "opening" grabbed my attention:

(a) <snip, historic reference to Boost-MPL and C++03 approaches>

(b) <snip, C++11 changed the playing field because of variadic templates
and associated parameter packs>

IMHO, we're "re-learning" the TMP thing with C++11, C++14, and C++17.  I've
been watching Boost-Hana closely, and it's kind of blowing my mind.

I particularly liked these two assertions:

>>
>> (a) mp_size to compute type-list length is a truly generic primitive
>> which is, "...so nice that [you'd] argue that all our metaprogramming
>> primitives ought to have this property."
>>
>> (b) "Lack-of-higher-order-metaprogramming", suggesting that in C++11 and
>> beyond, we largely should not need metafunctions such as compose, bind, or
>> a lambda library.
>>
>
> The only problem with (b) is that you can't define a template alias inside
> a function, which I myself found more than a bit annoying. Lambda functions
> a-la Hana have a distinct advantage here - they can be defined inside
> functions.
>
> Still. :-)
>

Good point, I'll have to think-on-that.  It doesn't take away from your
"main-thrust", though, which is that an extreme elegance is now possible
*without* metafunctions.  That's Really Nice, because they seem kind of
"klunky" to me, and I like the idea where we can increasingly get-away from
them.

The other thing that I wanted to mention (which I almost put in my first
response, but then took-it-out) is that I really agree with your approach
to use a prefix ("mp_" in your case) rather than relying on an enclosing
namespace.  I agree that it's nice to be able to exercise more control over
exactly what the compiler is finding-and-expanding without worrying about
weird namespace "discoveries".  ;-))

Again, thank you very much for the article:  It shouts loudly that we have
new and more elegant options for template metaprogramming, and I really
like the direction you suggest.

I really think yours is going to be one of those "classic-posts" that we'll
still be talking about for the next few years.  (So, if I ever run into
you, drinks are "on-me" -- you deserve it.)

--charley

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

pabristow
> -----Original Message-----
> From: Boost [mailto:[hidden email]] On Behalf Of charleyb123 .
> Sent: 30 May 2015 23:32
> To: [hidden email]
> Subject: Re: [boost] "Simple C++11 metaprogramming"

> > charleyb123 . wrote:
> >
> >  > http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html

> >> Very nice.  Very clean and impressive post.

+1

But there is a BIG error in the title - "Simple" and "C++11 metaprogramming" are incompatible!

Paul

PS My brain is hurting - and I haven't got to the end yet :-(

---
Paul A. Bristow
Prizet Farmhouse
Kendal UK LA8 8AB
+44 (0) 1539 561830





_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Vicente Botet
In reply to this post by Peter Dimov-2
Le 30/05/15 18:26, Peter Dimov a écrit :

> I've recently made the mistake to reread Eric Niebler's excellent
> "Tiny Metaprogramming Library" article
>
> http://ericniebler.com/2014/11/13/tiny-metaprogramming-library/
>
> which of course prompted me to try to experiment with my own tiny
> metaprogramming library and to see how I'd go about implementing
> tuple_cat (a challenge Eric gives.)
>
> Ordinarily, any such experiments of mine leave no trace once I abandon
> them and move on, but this time I decided to at least write an article
> about the result, so here it is, with the hope someone might find it
> useful. :-)
>
> http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>
Hi and thanks for the article.

I like very much the way you have reached to make generic meta functions
on type list. I'm curious which concept is behind all these erased type
list that are recognized as any type defined as

     template <class ... Ts> struct TL;

and for which TL<> is the neutral element respect to mp_append, but that
the real type is not as important as the type list it defines.
That is, what is important are the Ts... not the TL.

All these type list classes are in some way isomorphic. The query meta
functions have no issue, The single issue is when we need to construct a
type list, as we need a concrete type.


Your rational to use a prefix mp_ let me perplex. Does it mean that
namespaces have not reached its goal?

IMO, both mp_append_impl and mp_append are useful. Do you think that we
don't need any more the functionality of the mp_append_impl in
c++1/c++14? If you considered it still useful, maybe you can follow the
standard naming convention mp_append and mp_append_t.

A minor remark, the definition of

template<template<class...> class L1, class... T1,
     template<class...> class L2, class... T2, class... Lr>
     struct mp_append_impl<L1<T1...>, L2<T2...>, Lr...>
{
     using type = mp_append<L1<T1..., T2...>, Lr...>; // ***
};

could be

template<template<class...> class L1, class... T1,
     template<class...> class L2, class... T2, class... Lr>
     struct mp_append_impl<L1<T1...>, L2<T2...>, Lr...>
     : mp_append_impl<L1<T1..., T2...>, Lr...> // ****
{};

There is no need to forward reference append. Am I missing something
trivial?

The use of mp_list<> in mp_append_impl when there are 0 arguments is
weird. Just wondering if adding a
template <class ...> class R argument would make everything clearer. An
alternative is to not define it for 0 arguments.

I find weird also the use of mp_rename to apply a meta-function to a
type list.

It is annoying that we have a different syntax in c++ for type
construction and meta function classes. If the result of a template
alias could be directly another class template meta-function classes
would be simple type constructors. But the result must be a type, and so
we need to use a member class template (apply) to be able to return
meta-functions.

If something like this was possible

template <class T>
using x = template <class U> {};

Meta-function class could use this construction and then the syntax
would be the same. x<int> would be yet a class template and so  
x<int><int> would be possible.

E.g. the mp_constant

     template<class V> struct mp_constant
     {
             template<class...> using apply = V;
     };

             template<class L, class V> using mp_fill =
mp_transform<mp_constant<V>::template apply, L>;

could be

     template<class V>
         using mp_constant = template<class...> V;

             template<class L, class V> using mp_fill =
mp_transform<mp_constant<V>, L>;

But we don't have this. (Note: I'm not saying that introducing something
like that is an easy task, I have no idea of the consequences).

BTW, we have a name for lowering a MFC to a class template

template <class MFC>
using unquote = MFC::template apply

In the same way we have added suffix _t, we could add suffix _f for the
corresponding MFC

using add_pointer_f = quote<add_pointer_t>;

You are right that it is simple to write

template <template <class> class F, class X>
using twice = F<F,X>>;

template <class X>
struct two_pointers
   : twice<add_pointer_t, X>
{};

than

template <class F, class X>
using twice = apply<F, apply<F,X>>;

template <class X>
struct two_pointers
   : twice<lambda<add_pointer<_1> >, X>
{};

The first works better with the type traits _t extensions

     is_same<twice< add_pointer_t, int>, int**>

If we had some MFC  add_pointer_f (take another example)

struct add_pointer_f
{
     template <class T>
     struct apply : add_pointer_t<T> {};
};


then we would need to unquote

     is_same<twice< unquote<add_pointer_f>, int>, int**>

Following your design there is no reason for tuple_cat_ to works only
with mp_list.

template<class R, template<class...> class I, class...Is,
               template<class...> class K, class... Ks, class Tp>
R tuple_cat_( I<Is...>, K<Ks...>, Tp tp )
{
     return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
}

The name of the templates I and K are not important.


High order meta-programming appears as soon as you want a meta-function
to return a meta-function. This kind of meta-functions are at the origin
of meta-function classes.

I don't agree with you that it is preferable to define off line
meta-functions as in

     template<class... T> using Fgh = F<G<H<T...>>>;
or
     template<class L> using F = mp_iota<mp_size<L>>;


if I don't have a good name. But good designers find always good names ;-)

     template<class T, class U> using sizeof_less = mp_bool<(sizeof(T) <
sizeof(U))>;

If one day we have static constexpr lambdas, wouldn't we be able to use
some kind of lambda meta-functions as well.
Is not that what the proposed Boost.Hana and Boost.Fit  do already using
a specific trick?

STATIC_LAMBDA(T, U) { return sizeof(T) < sizeof(U); };

Thanks for sharing your ideas,
Vicente

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Peter Dimov-2
Vicente J. Botet Escriba wrote:
> Your rational to use a prefix mp_ let me perplex. Does it mean that
> namespaces have not reached its goal?

Namespaces work well most of the time, but metaprogramming is a bit of a
special case, because many of the identifiers we'd like to use in a
metaprogramming library are either keywords (if, int, false) or already
exist in namespace std (list, fill). The former forces us to add the suffix
_ at times, the latter has been known to create problems via
argument-dependent lookup.

It's of course possible to use a namespace, meta:: as in Eric's library, or
perhaps mp::, but I don't think that it buys us much.

> IMO, both mp_append_impl and mp_append are useful. Do you think that we
> don't need any more the functionality of the mp_append_impl in c++1/c++14?
> If you considered it still useful, maybe you can follow the standard
> naming convention mp_append and mp_append_t.

The point I am making by not using the standard _t convention is that in
C++11 aliases should be our primary primitive. The origin of the _t
convention is that the ordinary non-_t traits were there first because there
was no other way, and then the _t convenience aliases were added as an
afterthought. This is a historical artifact. A C++11 design that does not
have its origins in C++03 could and should choose the non-_t name for the
alias.

> The use of mp_list<> in mp_append_impl when there are 0 arguments is
> weird. Just wondering if adding a template <class ...> class R argument
> would make everything clearer.

The "idiomatic" way of making mp_append use a specific R is mp_append<R<>,
...>, which is not that much harder to use than the hypothetical
mp_append<R, ...>.

As a general rule, I prefer to keep functions homogeneous if possible.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

David Stone
Unfortunately, alias templates are not always the primary way of defining
something (they are, however, the primary way of using something). The
problem is that you cannot specialize an alias template, which is essential
in much metaprogramming. I've seen the convention of _c for the class
version, so the alias template that people actually use can be uncluttered
of suffixes. _impl works just as well.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Paul Fultz II
In reply to this post by Vicente Botet

> If one day we have static constexpr lambdas, wouldn't we be able to use
> some kind of lambda meta-functions

We don't need constexpr lambdas to achieve this. We can do higher-order type
computations using dependent typing. I show here how to implement boost fusion
filter so it will take a lambda rather than a MPL placeholder expression:

http://pfultz2.com/blog/2015/01/24/dependent-typing/

Which is based on the ideas presented by Zach Laine and Matt Calabrese several
years ago at boostcon. So in essence you can write this in C++14:

    auto numbers = simple_filter(some_fusion_sequence, [](auto x)
    {
        return is_integral<decltype(x)>() or is_floating_point<decltype(x)>();
    });

There is no `constexpr` required by the user. It all happens through dependent
typing. This is how Boost.Hana works as well. Furthermore, Boost.Hana is not
`constexpr`-metaprogramming(athough it makes use of `constexpr`), it is actually
dependently-typed metaprogramming, which is much more powerful in current C++.

> Is not that what the proposed Boost.Hana and Boost.Fit  do already using
> a specific trick?

That trick, in general, is only used to achieve `constexpr` initialization of
lambdas, which is necessary when declaring global lambdas. In can be used in
other ways to allow type deduction of lambdas in a `constexpr` context. However,
in general, with dependently-typed metaprogramming this isn't necessary.

Paul
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Bruno Dutra
In reply to this post by Peter Dimov-2
2015-05-30 13:26 GMT-03:00 Peter Dimov <[hidden email]>:

> I've recently made the mistake to reread Eric Niebler's excellent "Tiny
> Metaprogramming Library" article
>
> http://ericniebler.com/2014/11/13/tiny-metaprogramming-library/
>
> which of course prompted me to try to experiment with my own tiny
> metaprogramming library and to see how I'd go about implementing tuple_cat
> (a challenge Eric gives.)
>
> Ordinarily, any such experiments of mine leave no trace once I abandon
> them and move on, but this time I decided to at least write an article
> about the result, so here it is, with the hope someone might find it
> useful. :-)
>
> http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html
>

Very didactic overview on C++11 metaprogramming, I find many of your points
of view very much aligned to my own. I do believe however some of your
assumptions are a bit to hasty.

Higher order constructs, such as argument binding, are necessary in order
to enable a truly expressive functional idiom and template aliases can't
possibly make for a reasonable substitute for them. The need for so called
metafunction-classes arises most naturally as soon as one decides to write
a metafunction that returns another metafunction. As pointed out by
Vincente Escriba, template aliases can't allow for an indistinguishable
handling of metafunctions and variables (that is types), for the obvious
reason they can't match template type parameters.

Another thing that I believe has been overlooked, is the fact that the
property of lazy evaluation is entirely lost by directly typedef'ing
metafunctions as their result and, along with it, goes SFINAE friendliness
as well, or at least it becomes much trickier to pull. The ability to use
SFINAE as a means to select between alternative implementations is, I dare
say, the main reason why one decides to go all the way through
metaprogramming to begin with.

While I'm at it, I see that there's a widespread rejection to MPL's
typename <...>::type idiom but I fail to grasp the reason why. Sure one
might find it cumbersome to write it over and over again, but that's a
solved problem and has always been. MPL provides lambda<> and the
accompanying apply<> which elegantly overcome this cumbersomeness by
greatly reducing the necessity to sprinkle typename <...>::type all over
the place.

Taken from your article

typedef
    typename add_reference<
        typename add_const<
            typename add_pointer<X>::type
        >::type
    >::type Xpcr;

becomes simply

using Xpcr = typename apply<add_reference<add_const<add_pointer<_1>>>, X>::type;

and even if that single typename <>::type is found too much to bear, one
has now the option to adopt the C++14 convention and define apply_t
accordingly.

The most important thing to realize here, however, is the fact one retains
the option to lazily eval the expression if so desired, or rather required
in a SFINAE context. That is to say, typename <>::type must be regarded as
a feature, not as an awkward implementation detail.

I urge you to refrain from using C++11 so promptly as an excuse to deem MPL
obsolete. It has been the de facto metaprogramming library for over a
decade now for a good reason and, in my opinion, C++11 is not changing that
any time soon. Sure there are now other very elegant alternatives, Hana and
many others are there to prove it, but I don't see why deprecating a
library whose simplicity has allowed support of a remarkable number of
compilers still in production use today, many of which can't cope with the
newest C++14 constructions yet.

*Bruno C. O. Dutra*

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Peter Dimov-2
Bruno Dutra wrote:
> The need for so called metafunction-classes arises most naturally as soon
> as one decides to write a metafunction that returns another metafunction.
> As pointed out by Vincente Escriba, template aliases can't allow for an
> indistinguishable handling of metafunctions and variables (that is types),
> for the obvious reason they can't match template type parameters.

I actually know all that. That's kind of the point.

You can't just say "we need higher-order metaprogramming to return
metafunctions from metafunctions" - this is a tautology. This is what
"higher-order metaprogramming" means. You're basically saying that we need
higher-order metaprogramming to do higher-order metaprogramming. True but
trivial.

There obviously do exist occasions that call for higher-order
metaprogramming. The question is can we get by in 97% of the cases without
it. Not whether it's useful, but whether it's indispensable. Whether there's
a room for a "simple" metaprogramming library that doesn't provide
higher-order constructs and is therefore based on template aliases and not
on metafunction classes, and whether such a library can be adequately useful
for real world tasks. (I'm open to the possibility that the answer is "no",
but I'd like it to be "yes".)


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Bruno Dutra
2015-06-01 20:55 GMT-03:00 Peter Dimov <[hidden email]>:

> You can't just say "we need higher-order metaprogramming to return
> metafunctions from metafunctions" - this is a tautology. This is what
> "higher-order metaprogramming" means. You're basically saying that we need
> higher-order metaprogramming to do higher-order metaprogramming. True but
> trivial.
>

My choice of words might have been unfortunate, I was just trying to draw
attention to the fact that even if argument binding and all those bells and
whistles aren't necessary, metafunctions returning metafunctions alone
would call for metafunction-classes. Still, laziness and SFINAE
friendliness are the properties I deem most fundamental on any
metaprogramming library.


> There obviously do exist occasions that call for higher-order
> metaprogramming. The question is can we get by in 97% of the cases without
> it. Not whether it's useful, but whether it's indispensable. Whether
> there's a room for a "simple" metaprogramming library that doesn't provide
> higher-order constructs and is therefore based on template aliases and not
> on metafunction classes, and whether such a library can be adequately
> useful for real world tasks. (I'm open to the possibility that the answer
> is "no", but I'd like it to be "yes".)
>

I get the point, the question I raise is: "is MPL all that complex in a
C++11 world?"

After long discussions on this list a couple of months ago I decided to
experiment with rewriting MPL from scratch using C++11 as a starting point.
So far I have its "metafunctional" halve, that is, the part deals with
higher order metaprogramming, fairly mature, to the point I'm preparing to
document it.
What I've found, is that by using C++11 constructs it becomes much simpler
and, I dare say, intuitive than good old MPL. I argue, that perhaps that's
just simple enough.

As soon as I have it documented I'll share on this list, but If you'd be
interested in taking a look at it before I'm able to do so, you can find it
here:
https://github.com/brunocodutra/mpl2/tree/master/include/boost/mpl2/metafunctional

Unit tests, that serve as examples, can be found here:
https://github.com/brunocodutra/mpl2/tree/master/test/metafunctional

*Bruno C. O. Dutra*

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Joel de Guzman
In reply to this post by Peter Dimov-2
On 6/2/15 7:55 AM, Peter Dimov wrote:
> There obviously do exist occasions that call for higher-order metaprogramming. The
> question is can we get by in 97% of the cases without it. Not whether it's useful, but
> whether it's indispensable. Whether there's a room for a "simple" metaprogramming library
> that doesn't provide higher-order constructs and is therefore based on template aliases
> and not on metafunction classes, and whether such a library can be adequately useful for
> real world tasks. (I'm open to the possibility that the answer is "no", but I'd like it to
> be "yes".)

+10 This is exactly what I've been saying the past year or so. This seems the
consensus among people who have "been there and done that". I personally am
avoiding fancy TMP libraries now in favor of simpler mechanisms.

Regards,
--
Joel de Guzman
http://www.ciere.com
http://boost-spirit.com
http://www.cycfi.com/


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Peter Dimov-2
In reply to this post by Bruno Dutra
Bruno Dutra wrote:

> Still, laziness and SFINAE friendliness are the properties I deem most
> fundamental on any metaprogramming library.

I meant to respond to these points too.

The eagerness of template aliases is an obvious problem in at least one
place and that place is mp_if, where the naive mp_if<P<T>, F<T>, G<T>>
evaluates both F<T> and G<T>. But I'm not sure if there are others, under
the assumption that we've no higher-order constructs. Eric Niebler's meta
has an entire lazy:: namespace with deferred copies of all its constructs;
continuing the general theme, I wonder whether all this is strictly needed
once we jettison the lambda part.

SFINAE friendliness can be quite a curse. It often transforms reasonably
comprehensible error messages into full-scale Agatha Christie mysteries (the
compiler output even being of comparable length). So I'm not convinced (at
the moment) that a metaprogramming library should be SFINAE-friendly. I
presently tend to lean towards the philosophy of static_assert'ing as much
as possible, and leaving the primary templates undefined instead of empty.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Paul Fultz II
> SFINAE friendliness can be quite a curse. It often transforms reasonably
> comprehensible error messages into full-scale Agatha Christie mysteries (the
> compiler output even being of comparable length). So I'm not convinced (at
> the moment) that a metaprogramming library should be SFINAE-friendly.

Yep, this is something where compilers need to improve. It should treat the
diagnostic to undefined template instantiation the same way as overload
resolution failure. This way you can have a trace back to the original error,
instead of showing a bunch of unrelated errors.

Paul
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Bruno Dutra
In reply to this post by Peter Dimov-2
On Jun 2, 2015 7:43 AM, "Peter Dimov" <[hidden email]> wrote:

>
> Bruno Dutra wrote:
>
>> Still, laziness and SFINAE friendliness are the properties I deem most fundamental on any metaprogramming library.
>
>
> I meant to respond to these points too.
>
> The eagerness of template aliases is an obvious problem in at least one place and that place is mp_if, where the naive mp_if<P<T>, F<T>, G<T>> evaluates both F<T> and G<T>. But I'm not sure if there are others, under the assumption that we've no higher-order constructs. Eric Niebler's meta has an entire lazy:: namespace with deferred copies of all its constructs; continuing the general theme, I wonder whether all this is strictly needed once we jettison the lambda part.
>
> SFINAE friendliness can be quite a curse. It often transforms reasonably comprehensible error messages into full-scale Agatha Christie mysteries (the compiler output even being of comparable length). So I'm not convinced (at the moment) that a metaprogramming library should be SFINAE-friendly. I presently tend to lean towards the philosophy of static_assert'ing as much as possible, and leaving the primary templates undefined instead of empty.

That was *exactly* my approach in the beginning of my endeavor to
rewrite MPL, but that was only untill I had to write the first trait
introspection and realized static_assert'ions are not SFINAE friendly.

The need for laziness and SFINAE friendliness arises most clearly when
one is faced with a decision problem, whereby one is in the need for a
predicate such as is_evaluable<>, which expects a metafunction (a
variadic template template parameter in your case) and a variadic set
of arguments, and has to decided whether evaluating such metafunction
for the given set of arguments yields a valid result or errors out.
Errors could be due to arity mismatch or the incompleteness of the
instantiated template for example, but of course such predicates are
expected to dodge any such traps and yield either true_type or
false_type accordingly.

Perhaps one could go by without such predicates, but that would feel
just too crippling, it would be like programming C without branching.
Or maybe one should bite the bullet and rely on a lazy backend to
allow for such predicates (see below), but then why not exposing the
lazy backend to the end user if it's already there?

That's why I decided to follow a mixed approach, providing both lazy
and eager versions of metafunctions via the typename $<>::type and
$_t<> duality introduced by C++14.

//traits example using a lazy backend
#include <type_traits>

template<typename> struct test_c;
template<> struct test_c<void>{using type = void;};
template<typename _> using test = typename test_c<_>::type;

template<template<typename...> class f, typename... args>
struct is_evaluable_c
{
    template<template<typename...> class g, typename = g<args...>>
    static std::true_type check(int);
    template<template<typename...> class>
    static std::false_type check(...);

    using type = decltype(check<f>(0));
};

template<template<typename...> class f, typename... args>
using is_evaluable = typename is_evaluable_c<f, args...>::type;

static_assert(is_evaluable<test, void>::value, "");
static_assert(!is_evaluable<test, int>::value, "");
static_assert(!is_evaluable<test, void, int>::value, "");

Bruno Dutra

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Peter Dimov-2
Bruno Dutra wrote:
> //traits example using a lazy backend
...
> template<typename _> using test = /*...*/
...
> template<template<typename...> class f, typename... args>
> using is_evaluable = /*...*/
>
> static_assert(is_evaluable<test, void>::value, "");
> static_assert(!is_evaluable<test, int>::value, "");
> static_assert(!is_evaluable<test, void, int>::value, "");

Where is the laziness here? The user sees test<> (an alias), is_evaluable<>
(an alias), and the static asserts don't refer to anything else.

If I add another metafunction (in my sense, i.e. a template alias)

template<class T> using test2 = test<std::decay_t<T>>;

that has no lazy test2_c backend, is_evaluable still works for it:

static_assert(is_evaluable<test2, void const volatile>::value, "");
static_assert(!is_evaluable<test2, int()>::value, "");
static_assert(!is_evaluable<test2, void, int>::value, "");


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Zach Laine
In reply to this post by Joel de Guzman
On Mon, Jun 1, 2015 at 9:32 PM, Joel de Guzman <[hidden email]> wrote:

> On 6/2/15 7:55 AM, Peter Dimov wrote:
>
>> There obviously do exist occasions that call for higher-order
>> metaprogramming. The
>> question is can we get by in 97% of the cases without it. Not whether
>> it's useful, but
>> whether it's indispensable. Whether there's a room for a "simple"
>> metaprogramming library
>> that doesn't provide higher-order constructs and is therefore based on
>> template aliases
>> and not on metafunction classes, and whether such a library can be
>> adequately useful for
>> real world tasks. (I'm open to the possibility that the answer is "no",
>> but I'd like it to
>> be "yes".)
>>
>
> +10 This is exactly what I've been saying the past year or so. This seems
> the
> consensus among people who have "been there and done that". I personally am
> avoiding fancy TMP libraries now in favor of simpler mechanisms.
>

Yes.  A thousand times yes.

TMP gets even easier with some of the C++14 features, so much so that I
keep wondering if I'll ever use MPL (or the type-computation-only portion
of Hana) again.

Zach

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: "Simple C++11 metaprogramming"

Bruno Dutra
In reply to this post by Peter Dimov-2
On Jun 2, 2015 10:03 AM, "Peter Dimov" <[hidden email]> wrote:

>
> Bruno Dutra wrote:
>>
>> //traits example using a lazy backend
>
> ...
>>
>> template<typename _> using test = /*...*/
>
> ...
>>
>> template<template<typename...> class f, typename... args>
>> using is_evaluable = /*...*/
>>
>>
>> static_assert(is_evaluable<test, void>::value, "");
>> static_assert(!is_evaluable<test, int>::value, "");
>> static_assert(!is_evaluable<test, void, int>::value, "");
>
>
> Where is the laziness here? The user sees test<> (an alias),
is_evaluable<> (an alias), and the static asserts don't refer to anything
else.

That's the point, one stretches long lengths to provide laziness under the
hood and yet deprives the end user to make direct use of it, despite the
fact it allows for useful features, such as lazy branching.

> If I add another metafunction (in my sense, i.e. a template alias)
>
> template<class T> using test2 = test<std::decay_t<T>>;
>
> that has no lazy test2_c backend, is_evaluable still works for it:
>
> static_assert(is_evaluable<test2, void const volatile>::value, "");
> static_assert(!is_evaluable<test2, int()>::value, "");
> static_assert(!is_evaluable<test2, void, int>::value, "");

What you mean? std::decay<>::type is the lazy backend. That's actually an
example of the point I'm trying to make here,  std::decay_t<> is and should
be provided only as a shorthand for its lazy counterpart, without, however,
attempting to replace it, simply because it can't. That is, the lazy
version remains available to the end users if needed.

Bruno Dutra

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
123