c++boostboost-mpl

Obtain regular MPL list from push_front operation


I am using Boost.MPL, I have a compile-time list (boost::mpl::list). When I push back an element, I get something that is probably equivalent to a list but is not an boost::mpl::list.

#include <boost/mpl/list.hpp>
int main(){
    using l = boost::mpl::push_front<boost::mpl::list<int, double, std::string>, char>::type;
}

l is boost::mpl::l_item<mpl_::long_<4>, char, boost::mpl::list3<int, double, std::__cxx11::basic_string<char> > >

How can I transfrom l into a proper boost::mpl::list<char, int, double, std::string>?

In Boost.Fusion we have boost::fusion:as_list, but I cannot find the equivalent function in Boost.MPL.


Solution

  • You can achieve that with a custom type by implementing a push_back MPL operator for it.

    #include <boost/mpl/list.hpp>
    #include <boost/mpl/copy.hpp>
    #include <boost/mpl/back_inserter.hpp>
    #include <string>
    #include <type_traits>
    #include <tuple>
    
    
    struct type_pack_tag;
    
    template <typename... T>
    struct type_pack
    {
        using tag = type_pack_tag; // MPL tag
    
        template <typename... U>
        using append = type_pack<T..., U...>;
    
        template <template <typename...> class F>
        using transfer = F<T...>;
    };
    
    namespace boost { namespace mpl {
    
    template <>
    struct push_back_impl<type_pack_tag>
    {
        template <typename TypePack, typename T> struct apply
        {
            using type = typename TypePack::template append<T>;
        };
    };
    
    }}
    
    // Just a shortcut
    template <template <typename...> class F, typename T>
    using transfer_mpl_seq_to_t =
        typename boost::mpl::copy<
            T, boost::mpl::back_inserter<type_pack<>>
        >::type::template transfer<F>;
    
    int main()
    {
        using l = boost::mpl::push_front<boost::mpl::list<int, double, std::string>, char>::type;
    
        using pack = boost::mpl::copy<l, boost::mpl::back_inserter<type_pack<>>>::type;
        static_assert(std::is_same<pack, type_pack<char, int, double, std::string>>::value, "must be equal");
        static_assert(std::is_same<pack::transfer<boost::mpl::list>, boost::mpl::list<char, int, double, std::string>>::value, "must be equal");
    
        // Test the shortcut
        static_assert(std::is_same<transfer_mpl_seq_to_t<boost::mpl::list, l>, boost::mpl::list<char, int, double, std::string>>::value, "must be equal");
        static_assert(std::is_same<transfer_mpl_seq_to_t<std::tuple, l>, std::tuple<char, int, double, std::string>>::value, "must be equal");
    }
    

    If you just need to instantiate an std::tuple with types of MPL sequence:

    #include <boost/mpl/sequence_tag_fwd.hpp>
    #include <boost/mpl/list.hpp>
    #include <boost/mpl/copy.hpp>
    #include <boost/mpl/back_inserter.hpp>
    #include <string>
    #include <type_traits>
    #include <tuple>
    
    
    struct std_tuple_tag;
    
    namespace boost { namespace mpl {
    
        template <typename... T>
        struct sequence_tag<std::tuple<T...>>
        {
            typedef std_tuple_tag type;
        };
    
    }}
    
    
    namespace boost { namespace mpl {
    
    template <>
    struct push_back_impl<std_tuple_tag>
    {
        template <typename Tuple, typename T> struct apply;
    
        template <typename... T, typename AppendT>
        struct apply<std::tuple<T...>, AppendT>
        {
            using type = std::tuple<T..., AppendT>;
        };
    };
    
    }}
    
    int main()
    {
        using l = boost::mpl::push_front<boost::mpl::list<int, double, std::string>, char>::type;
    
        using tpl = boost::mpl::copy<l, boost::mpl::back_inserter<std::tuple<>>>::type;
        static_assert(std::is_same<tpl, std::tuple<char, int, double, std::string>>::value, "must be equal");
    }
    

    Or even simpler:

    #include <boost/mpl/list.hpp>
    #include <boost/mpl/copy.hpp>
    #include <boost/mpl/back_inserter.hpp>
    #include <string>
    #include <type_traits>
    #include <tuple>
    
    
    namespace boost { namespace mpl {
    
    template <typename... T, typename AppendT>
    struct push_back<std::tuple<T...>, AppendT>
    {
        using type = std::tuple<T..., AppendT>;
    };
    
    }}
    
    int main()
    {
        using l = boost::mpl::push_front<boost::mpl::list<int, double, std::string>, char>::type;
    
        using tpl = boost::mpl::copy<l, boost::mpl::back_inserter<std::tuple<>>>::type;
        static_assert(std::is_same<tpl, std::tuple<char, int, double, std::string>>::value, "must be equal");
    }