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. :-)
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