Search code examples
c++boosttemplate-meta-programmingboost-mpl

Getting the first M elements of an mpl vector


I have a boost::mpl::vector with N elements, say:

typedef boost::mpl::vector<int,float,double,short,char> my_vector;

I wish to obtain a sequence containing the first M elements of my_vector. So if M is 2 I want out a:

typedef boost::mpl::vector<int,float> my_mvector;

Initially I thought of using erase<s,first,last> but was unable to figure out suitable template parameters for first and last. (I was using at_c<...>::type.) However, it is also my understanding that filter_view can also be used for the task. What is the best way of going about this?


Solution

  • Erase is a reasonable solution for your problem.

    • The value you want for first is the result of mpl::begin<T> which is advanced by the number of elements you are interested in returning.
    • The value you want for end is the result of mpl::end<T>

    The code below assumes that you want the metafunction to return the original type if the number of elements in the vector is less than the requested number. It's also possible to use a static assertion to verify that input integral type is less than or equal to the size of the vector.

    I provied both a first_n_elements which takes an MPL integral constant and first_n_elements_c which simply takes an integer.

    You could also use iterator_range<> along with the begin and cut iterators in the below code, if you want to use a view. I'm not sure what the advantages are of one over the other in this case.

    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/size.hpp>
    #include <boost/mpl/erase.hpp>
    #include <boost/mpl/eval_if.hpp>
    #include <boost/mpl/int.hpp>
    #include <boost/mpl/less.hpp>
    namespace mpl = boost::mpl;
    
    
    
    namespace detail 
    {
      // Note, this is an internal detail.  Please use the structures below
      template <typename T, typename N>
      struct erase_after_n
      {
        typedef typename mpl::begin<T>::type begin_iter;
        typedef typename mpl::advance<begin_iter, N>::type cut_iter;
        typedef typename mpl::end<T>::type end_iter;
    
        typedef 
        typename mpl::erase< T,cut_iter, end_iter >::type type;
    
      };
    
    }
    
    
    template <typename T, typename N> 
    struct first_n_elements
    {
      typedef 
      typename mpl::eval_if< mpl::less < mpl::size<T>, N >,
                 T,
                 detail::erase_after_n<T, N> >::type type;
    
    };
    
    template <typename T, int N> 
    struct first_n_elements_c
    {
      typedef 
      typename first_n_elements<T, mpl::int_<N> >::type type ;
    
    };