//References:
//  [apply.html]
//    http://www.boost.org/doc/libs/1_38_0/libs/mpl/doc/refmanual/apply.html
//  [fold.html]
//    http://www.boost.org/doc/libs/1_38_0/libs/mpl/doc/refmanual/fold.html
//  
//Purpose:
//  Demonstrate that either there's a bug in either [apply.hpp] or [fold.html]
//

#include <boost/mpl/range_c.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/iter_fold.hpp>

#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/assert.hpp>

using namespace boost::mpl;
using namespace placeholders;

namespace test_io
{//input/outputs to test

  template
  < typename N1
  , typename N2 
  > 
struct int_plus
  : int_<( N1::value + N2::value )>
{
};
    typedef 
  int_plus< _1, _2> 
op
;
     typedef
  range_c
  < int
  , 3
  , 5
  >
seq
;
    typedef
  int_<1>
state0
;
    typedef
  int_<8>
fold_expected
;
}//exit test_io namespace
namespace fold_good
{
  using namespace test_io
  ;
    typedef
  fold
  < seq
  , state0
  , op
  >::type
fold_actual
;
BOOST_MPL_ASSERT(( equal_to<fold_actual,fold_expected> ));
}//exit fold_good namespace

//#define FOLD_BUG
#ifdef FOLD_BUG
namespace apply_iter_bad
{
  using namespace test_io
  ;
    typedef
  iter_fold
  < seq
  , state0
  , apply2
    < op
    , _1
    , deref<_2> 
    >
  >::type
iter_apply
//This fails to compile despite being an almost exact copy
//of the code shown in [fold.html].
;
//BOOST_MPL_ASSERT(( equal_to<iter_apply,fold_expected> ));
}//exit apply_iter_bad namespace
#endif

namespace wrap_iter_good
{
  using namespace test_io
  ;
    typedef
  iter_fold
  < seq
  , state0
  , apply_wrap2
    < lambda<op>::type
    , _1
    , deref<_2> 
    >
  >::type
iter_wrap
//This compiles OK & passes following test OK.
//
//What's puzzling about this is that, according to:
//  http://www.boost.org/doc/libs/1_38_0/libs/mpl/doc/refmanual/apply.html
//the expresion:
//  apply<op,a1,a2> 
//is supposed to be equivalent to:
//  apply_wrap2<lambda<op.::type,a1,a2>
//This equivalence is supported by looking at the -E compiler output
//which contains:
/*
      template 
      < typename F
      , typename T1
      , typename T2 
      > 
    struct apply2
    : apply_wrap2 
      < typename lambda < F >::type
      , T1
      , T2 
      >
    {
    };

 */
//CONCLUSION:
//  The compiler used  to show the iter_apply failure
//  (gcc4.1) must be buggy.
;
BOOST_MPL_ASSERT(( equal_to<iter_wrap, fold_expected > ));
}//exit wrap_iter_good namespace
namespace apply_apply_iter
{//test apply<apply<...>,,>
  using namespace test_io
  ;
      typedef
    begin<seq>::type
  iter0
  ;
      typedef
    apply
    < op
    , state0
    , deref<iter0>::type
    >::type
  apply_expected
  ;
#if 0
      typedef
    apply
    < apply
      < op
      , _1
      , deref<_2>
      >
    , state0
    , iter0
    >::type
  apply_apply
  //This fails to compile.
  ;
//BOOST_MPL_ASSERT(( equal_to<apply_apply, apply_expected > ));
#endif
#if 1 
      typedef
    apply
    < apply_wrap2
      < lambda<op>::type
      , _1
      , deref<_2>
      >
    , state0
    , iter0
    >::type
  apply_wrap_lambda
  //This compiles and passes following test.
  ;
  BOOST_MPL_ASSERT(( equal_to<apply_wrap_lambda, apply_expected > ));
#endif
}//exit apply_apply_iter
