|
Boost : |
Subject: Re: [boost] "Simple C++11 metaprogramming"
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2015-05-31 05:02:57
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk