// (by Ariel Badichi) #include <boost/static_assert.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/divides.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/begin.hpp> #include <boost/mpl/end.hpp> #include <boost/mpl/advance.hpp> #include <boost/mpl/iterator_range.hpp> #include <boost/mpl/clear.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/times.hpp> #include <boost/mpl/back_inserter.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/insert_range.hpp> #include <boost/mpl/placeholders.hpp>
namespace mpl = boost::mpl; using namespace mpl::placeholders;
template<typename Seq> struct double_first_half { typedef mpl::int_<2> two; typedef typename mpl::divides<mpl::size<Seq>, two>::type half_size; typedef typename mpl::begin<Seq>::type first; typedef typename mpl::advance<first, half_size>::type mid; typedef typename mpl::end<Seq>::type last; typedef typename mpl::iterator_range<first, mid> first_half; typedef typename mpl::iterator_range<mid, last> second_half; typedef typename mpl::transform< first_half, mpl::times<_, two>, mpl::back_inserter<mpl::vector<> > >::type doubled_half; typedef typename mpl::insert_range< doubled_half, typename mpl::end<doubled_half>::type, second_half >::type type; };
int main() { typedef mpl::vector_c<int, 1, 2, 3, 4> input; typedef mpl::vector_c<int, 2, 4, 3, 4> expected; typedef double_first_half<input>::type actual;
BOOST_STATIC_ASSERT((mpl::equal<expected, actual>::type::value));
return 0; }
Just a quick note: the double_first_half presented here always "returns" the result in an mpl::vector. If you're willing to only work with extensible sequences (or do some specializations for such), you can use:
typedef typename mpl::transform< first_half, mpl::times<_, two>, mpl::back_inserter<typename mpl::clear<Seq>::type> >::type doubled_half;
By calling clear on the Seq, you return the same type as the argument. The question specifies a Random Access Sequence, which problably means mpl::vector , but calling clear is little more general when dealing with extensible sequences.
Initially, I had written a different solution that did use mpl::clear (notice the funny #include for clear.hpp) but this feature somehow got lost. Thanks for the remark! - Ariel
My main answer looks very similar to the above, but I also came up with a more succint, yet less efficient way to do it. Presented here only for curiousity and as a technique that might be useful in other situations. Basically you use the two argument form of mpl::transform, along with range_c to create an enumeration of the elements in the sequence. The requirements on Seq are relaxed as well,as I believe this should work with any Forward Sequence. In code:
template <typename Seq> struct double_first_half: mpl::transform< Seq, mpl::range_c<int, 0, mpl::size<Seq>::value>, mpl::if_< mpl::less<_2, mpl::int_<mpl::size<Seq>::value / 2> >, mpl::times<_1, mpl::int_<2> >, _1 > > { };