[Home]CPPTM Answers - Exercise 5-1

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

 // (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 > >
	{
	};

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited March 28, 2005 10:31 am (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers