// (by Ariel Badichi) #include <boost/static_assert.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/next.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/not_equal_to.hpp> #include <boost/mpl/greater.hpp> #include <boost/mpl/minus.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/multiplies.hpp>
namespace mpl = boost::mpl;
// 4-3.1
template<typename N, typename Predicate> struct next_if : mpl::eval_if< mpl::apply<Predicate, N>, mpl::next<N>, N > {};
// 4-3.2
// formula runtime pseudo-code (I used this to write the tests) // // int formula(int n1, int n2) // { // if (n1 != n2) { // if (n1 > n2) // return n1 - n2; // else // return n1; // } else { // return n1 + (n1 * 2); // } // } //
template<typename N1, typename N2> struct formula : mpl::eval_if< mpl::not_equal_to<N1, N2>, mpl::eval_if< mpl::greater<N1, N2>, mpl::minus<N1, N2>, N1 >, mpl::plus< N1, mpl::multiplies< N1, mpl::int_<2> > > > {};
////////////////////////////////////////////////////////////////////////////// // Adriy Tylychko (telya at mail dot ru) // The solution above is correct but some "::type"'s don't need // to be removed to receive the same effect, so I think version: template< typename N1, typename N2 > struct formula : mpl::eval_if< mpl::not_equal_to<N1,N2> , typename mpl::eval_if< mpl::greater<N1,N2> , typename mpl::minus<N1,N2> , N1 >::type , typename mpl::plus< N1 , typename mpl::times< N1, mpl::int_<2> > > >::type {}; // is "more correct" :) ///////////////////////////////////////////////////////////////////
template<typename Nullary> struct make_class { template<typename> struct apply : Nullary {}; };
typedef make_class<mpl::false_> never; typedef make_class<mpl::true_> always;
int main() { typedef mpl::int_<1> one;
typedef next_if<one, never>::type still_one; BOOST_STATIC_ASSERT((still_one::type::value == 1));
typedef next_if<one, always>::type two; BOOST_STATIC_ASSERT((two::type::value == 2));
/////////////////////////////////////////////////////////////////////////////////////////////////// // Andriy Tylychko (telya at mail dot ru) // the solution above works because "adapted" predicates are used (ones that have nested "apply") // following example cannot be compiled, at least using VC8: BOOST_STATIC_ASSERT((next_if<mpl::int_<1>, mpl::equal_to<mpl::int_<1>, _> >::type::value == 2)); // to fix, "::type" shoul be returned to "mpl::apply<Predicate, N>", in any case this instantiation // cannot be ommitted. // So, final changes consist of: // a) change mpl::if_ to mpl::eval_if // b) remove "::type" from "typename mpl::next<N>::type" ///////////////////////////////////////////////////////////////////////////////////////////////////
BOOST_STATIC_ASSERT((formula<one, still_one>::type::value == 3)); BOOST_STATIC_ASSERT((formula<one, two>::type::value == 1)); BOOST_STATIC_ASSERT((formula<two, one>::type::value == 1));
return 0; }