[Home]CPPTM Answers - Exercise 4-2

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

Difference (from prior major revision) (no other diffs)

Added: 165a166,280

____________________________________________________________________________________________________


// by Noah Roberts - Engineered Software INC.

/*
** Original used a blank struct for default arguments. Took the idea of using bools and eval_if
** instead of if_ from Ariel Badichi's answer.
**
** This version adheres to the requirements just a touch better:
** (1) The MPL version of these operators accept a single argument, Badichi's does not.
** His version passes all of my tests except the last one.
**
** Also, this version causes warnings similar to the MPL version and has a shallower recursion when
** the final argument is not a bool_ type.
*/

#include <boost/static_assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/int.hpp>

using boost::mpl::_1;


template
<
typename T1
, typename T2 = boost::mpl::false_
, typename T3 = boost::mpl::false_
, typename T4 = boost::mpl::false_
, typename T5 = boost::mpl::false_
>
struct logical_or_ :
boost::mpl::eval_if<T1, T1, logical_or_<T2,T3,T4,T5,boost::mpl::false_> >
{};

// Termination clause
template <typename T1>
struct logical_or_<T1,boost::mpl::false_,boost::mpl::false_,boost::mpl::false_,boost::mpl::false_> :
boost::mpl::bool_<T1::type::value>
{};

template
<
typename T1
, typename T2 = boost::mpl::true_
, typename T3 = boost::mpl::true_
, typename T4 = boost::mpl::true_
, typename T5 = boost::mpl::true_
>
struct logical_and_ :
boost::mpl::eval_if<T1, logical_and_<T2,T3,T4,T5,boost::mpl::true_>, T1>
{};

// Termination clause
template <typename T1>
struct logical_and_<T1,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_> :
boost::mpl::bool_<T1::type::value>
{};

// Metafuction that takes metafunction as argument - for testing lambda expressions.
template < typename F, typename X >
struct twice
: boost::mpl::apply<F, typename boost::mpl::apply<F,X>::type>::type
{};

// Error tester - invalid metafunction.
struct error {};

int main(void)
{
using boost::mpl::true_;
using boost::mpl::false_;
using boost::mpl::_1;

// Same tests as previous exercize
BOOST_STATIC_ASSERT((logical_or_ < true_, true_ >::value));
BOOST_STATIC_ASSERT((logical_or_ < true_, false_ >::value));
BOOST_STATIC_ASSERT((logical_or_ < false_, true_ >::value));
BOOST_STATIC_ASSERT((!logical_or_ < false_, false_ >::value));
BOOST_STATIC_ASSERT((logical_or_<true_, error>::value));

// Test 5 args
BOOST_STATIC_ASSERT((logical_or_ < false_, false_, false_, false_, true_ >::value));
BOOST_STATIC_ASSERT((logical_or_ < false_, false_, false_, true_, error >::value));

// Same as previous exercize
BOOST_STATIC_ASSERT((logical_and_<true_, true_ >::value));
BOOST_STATIC_ASSERT((!logical_and_<true_, false_>::value));
BOOST_STATIC_ASSERT((!logical_and_<false_, true_>::value));
BOOST_STATIC_ASSERT((!logical_and_<false_, false_>::value));
BOOST_STATIC_ASSERT((!logical_and_<false_, error>::value));

// Test 5 args
BOOST_STATIC_ASSERT((!logical_and_<true_,true_,true_,true_,false_>::value));
BOOST_STATIC_ASSERT((!logical_and_<true_,true_,true_,false_,error>::value));

// Test lambda expressions
BOOST_STATIC_ASSERT((twice< logical_and_<true_, _1>, true_>::value));

// Test non-bool types - generates warnings on some platforms, but does compile and work with mpl versions.
using boost::mpl::int_;
BOOST_STATIC_ASSERT((logical_and_< int_<5>, int_<7> >::value));
BOOST_STATIC_ASSERT((!logical_and_< int_<5>, int_<0> >::value));

// MPL versions accept a single argument
BOOST_STATIC_ASSERT((logical_or_< true_ >::value));

return 0;
}


 // (by Ariel Badichi)
 #include <boost/static_assert.hpp>
 #include <boost/mpl/bool.hpp>
 #include <boost/mpl/eval_if.hpp>

 namespace mpl = boost::mpl;

 class error {}; // no ::type

 template<typename T1, typename T2, typename T3 = mpl::false_, typename T4 = mpl::false_, typename T5 = mpl::false_>
 struct logical_or : mpl::eval_if<T1, mpl::true_, logical_or<T2, T3, T4, T5, mpl::false_> > {};

 template<>
 struct logical_or<mpl::false_, mpl::false_, mpl::false_, mpl::false_, mpl::false_> : mpl::false_ {};

 template<typename T1, typename T2, typename T3 = mpl::true_, typename T4 = mpl::true_, typename T5 = mpl::true_>
 struct logical_and : mpl::eval_if<T1, logical_and<T2, T3, T4, T5, mpl::true_>, mpl::false_> {};

 template<>
 struct logical_and<mpl::true_, mpl::true_, mpl::true_, mpl::true_, mpl::true_> : mpl::true_ {};

 int main()
 {
     BOOST_STATIC_ASSERT((logical_or<mpl::true_, error>::type::value));
     BOOST_STATIC_ASSERT((!logical_or<mpl::false_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_or<mpl::false_, mpl::false_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_or<mpl::false_, mpl::false_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_or<mpl::false_, mpl::false_, mpl::false_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_or<mpl::false_, mpl::false_, mpl::false_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_or<mpl::false_, mpl::false_, mpl::false_, mpl::false_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_or<mpl::false_, mpl::false_, mpl::false_, mpl::false_, mpl::false_>::type::value));

     BOOST_STATIC_ASSERT((!logical_and<mpl::false_, error>::type::value));
     BOOST_STATIC_ASSERT((logical_and<mpl::true_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_and<mpl::true_, mpl::true_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_and<mpl::true_, mpl::true_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_and<mpl::true_, mpl::true_, mpl::true_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_and<mpl::true_, mpl::true_, mpl::true_, mpl::true_>::type::value));
     BOOST_STATIC_ASSERT((!logical_and<mpl::true_, mpl::true_, mpl::true_, mpl::true_, mpl::false_>::type::value));
     BOOST_STATIC_ASSERT((logical_and<mpl::true_, mpl::true_, mpl::true_, mpl::true_, mpl::true_>::type::value));

     return 0;
 }

__________________________________________________________________________________________________________________

 // By Constantin Fishkin (Coca)
 // Not using mpl::eval_if

 /**
 Exercise 4-2.
 Allow logical_or and logical_and to get up to 5 arguments
 */

 #include <boost/static_assert.hpp>
 #include <boost/type_traits/add_pointer.hpp>
 #include <boost/mpl/or.hpp>
 #include <boost/mpl/and.hpp>
 #include <boost/mpl/bool.hpp>

 #include <iostream>

 namespace mpl=boost::mpl;

 /** the structute does not have
 required members and can not be used
 with or_/and_
 */
 struct invalid_2
 {
 };

 /** General specialization for logic_or_imp is true_. This is the most
 common case because it comes true if at least one of parameters is true.
 */
 template<bool b, typename T2, typename T3, typename T4, typename T5> 
 struct logic_or_imp_5 : 
	mpl::true_
 {
 };

 /** Specialization when all parameters are false. It obviously gives us false_
 */
 template<> 
 struct logic_or_imp_5<false, false_, false_, false_, false_> : 
	mpl::false_
 {
 };

 /** Specialization when the first boolean argument is false. In this case
 we need to check first of others 4 arguments. To do so we will swicth the first and the last arguments
 and replace last argument with false_. Obviously it does not change value
 of logical expression. This template will be called recursively till first "true" 
 parameter will be found or all parameters will be checked. 
 The case when all parameters are found be "false" is the case above and it gives us false_
 */
 template<typename T2, typename T3, typename T4, typename T5> 
 struct logic_or_imp_5<false, typename T2, typename T3, typename T4, typename T5> : 
	logic_or_imp_5<T2::value, typename T3, typename T4, typename T5, false_>
 {
 };

 /** Implemantation of the logic_or that evaluates next parameters only if it is needed. 
 Note that it uses default values for all parameters after the second.
 */
 template<typename T1, typename T2, typename T3 = false_, typename T4 = false_, typename T5 = false_>  
 struct logic_or_5 : logic_or_imp_5< T1::value, T2, T3, T4, T5 >
 {
 };

 /** General specialization for logic_and_imp is false_. This is the most
 common case because it comes true if at least one of the parameters is false.
 */
 template<bool b, typename T2, typename T3, typename T4, typename T5> 
 struct logic_and_imp_5 : 
	mpl::false_
 {
 };

 /** Specialization when all parameters are true. It obviously gives us true_
 */
 template<> 
 struct logic_and_imp_5<true, true_, true_, true_, true_> : 
	mpl::true_
 {
 };

 /** Specialization when the first boolean argument is true. In this case
 we need to check first of others 4 arguments. To do so we will swicth the first and the last arguments
 and replace last argument with true_. Obviously it does not change value
 of logical expression. This template will be called recursively till first "false" 
 parameter will be found or all parameters will be checked. 
 The case when all parameters are found be "true" is the case above and it gives us true_
 */
 template<typename T2, typename T3, typename T4, typename T5> 
 struct logic_and_imp_5<true, typename T2, typename T3, typename T4, typename T5> : 
	logic_or_imp_5<T2::value, typename T3, typename T4, typename T5, true_>
 {
 };

 /** Implemantation of the logic_and that evaluates next parameters only if it is needed. 
 Note that it uses default values for all parameters after the second.
 */
 template<typename T1, typename T2, typename T3 = true_, typename T4 = true_, typename T5 = true_>  
 struct logic_and_5 : logic_and_imp_5< T1::value, T2, T3, T4, T5 >
 {
 };

 int main()
 {
	std::cout<<std::endl<<"Exercise 4.2"<<std::endl;	

	// compiler makes its decsion from the first
	// parameters and does not evaluate the rest
	logic_or_5<mpl::false_, mpl::false_, mpl::true_, invalid_2, invalid_2>::type::value;
	logic_or_5<mpl::false_, mpl::false_, mpl::true_, invalid_2>::type::value;

	// compiler makes its decsion from the first
	// parameters and does not evaluate the rest
	logic_and_5<mpl::false_, invalid_2>::type::value;
	logic_and_5<mpl::true_, mpl::true_, mpl::false_, invalid_2, invalid_2>::type::value;

        return 0;	
 }

____________________________________________________________________________________________________

// by Noah Roberts - Engineered Software INC.

/*
** Original used a blank struct for default arguments.  Took the idea of using bools and eval_if
** instead of if_ from Ariel Badichi's answer.
**
** This version adheres to the requirements just a touch better:
**  (1) The MPL version of these operators accept a single argument, Badichi's does not.
**      His version passes all of my tests except the last one.
**
** Also, this version causes warnings similar to the MPL version and has a shallower recursion when
** the final argument is not a bool_ type.
*/

#include <boost/static_assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/int.hpp>

using boost::mpl::_1;


template 
< 
    typename T1
  , typename T2 = boost::mpl::false_
  , typename T3 = boost::mpl::false_
  , typename T4 = boost::mpl::false_
  , typename T5 = boost::mpl::false_ 
>
struct logical_or_ :
  boost::mpl::eval_if<T1, T1, logical_or_<T2,T3,T4,T5,boost::mpl::false_> >
{};

// Termination clause
template <typename T1>
struct logical_or_<T1,boost::mpl::false_,boost::mpl::false_,boost::mpl::false_,boost::mpl::false_> :
  boost::mpl::bool_<T1::type::value>
{};

template 
< 
    typename T1
  , typename T2 = boost::mpl::true_
  , typename T3 = boost::mpl::true_
  , typename T4 = boost::mpl::true_
  , typename T5 = boost::mpl::true_ 
>
struct logical_and_ :
  boost::mpl::eval_if<T1, logical_and_<T2,T3,T4,T5,boost::mpl::true_>, T1>
{};

// Termination clause
template <typename T1>
struct logical_and_<T1,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_,boost::mpl::true_> :
  boost::mpl::bool_<T1::type::value>
{};

// Metafuction that takes metafunction as argument - for testing lambda expressions.
template < typename F, typename X >
struct twice
  : boost::mpl::apply<F, typename boost::mpl::apply<F,X>::type>::type
{};

// Error tester - invalid metafunction.
struct error {};

int main(void)
{
  using boost::mpl::true_;
  using boost::mpl::false_;
  using boost::mpl::_1;

  // Same tests as previous exercize
  BOOST_STATIC_ASSERT((logical_or_ < true_, true_ >::value));
  BOOST_STATIC_ASSERT((logical_or_ < true_, false_ >::value));
  BOOST_STATIC_ASSERT((logical_or_ < false_, true_ >::value));
  BOOST_STATIC_ASSERT((!logical_or_ < false_, false_ >::value));
  BOOST_STATIC_ASSERT((logical_or_<true_, error>::value));

  // Test 5 args
  BOOST_STATIC_ASSERT((logical_or_ < false_, false_, false_, false_, true_ >::value));
  BOOST_STATIC_ASSERT((logical_or_ < false_, false_, false_, true_, error >::value));

  // Same as previous exercize
  BOOST_STATIC_ASSERT((logical_and_<true_, true_ >::value));
  BOOST_STATIC_ASSERT((!logical_and_<true_, false_>::value));
  BOOST_STATIC_ASSERT((!logical_and_<false_, true_>::value));
  BOOST_STATIC_ASSERT((!logical_and_<false_, false_>::value));
  BOOST_STATIC_ASSERT((!logical_and_<false_, error>::value));

  // Test 5 args
  BOOST_STATIC_ASSERT((!logical_and_<true_,true_,true_,true_,false_>::value));
  BOOST_STATIC_ASSERT((!logical_and_<true_,true_,true_,false_,error>::value));

  // Test lambda expressions
  BOOST_STATIC_ASSERT((twice< logical_and_<true_, _1>, true_>::value));

  // Test non-bool types - generates warnings on some platforms, but does compile and work with mpl versions.
  using boost::mpl::int_;
  BOOST_STATIC_ASSERT((logical_and_< int_<5>, int_<7> >::value));
  BOOST_STATIC_ASSERT((!logical_and_< int_<5>, int_<0> >::value));

  // MPL versions accept a single argument
  BOOST_STATIC_ASSERT((logical_or_< true_ >::value));

  return 0;
}

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited May 2, 2008 12:45 pm (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers