#ifndef TESTS_RECURSE_HPP
#define TESTS_RECURSE_HPP
#include <boost/static_assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/bool.hpp>
//
// This file instantiates a recursive template, with compile-time
// assertions that fail if recursion reaches some depth.
//
// To use, include this header from somewhere
//
// Configuration:
//
// This will assert if recursion gets deeper than the constants
// "class_max_depth" and "function_max_depth" below. Change them
// to assert at some specific depth.
//
// "do_recurse" at the end of this file instantiates the templates.
// Change it to instantiate another depth.
//
namespace tests {

int const
  class_max_depth = 5, //assert at class scope at this detpth
  function_max_depth = 4; //assert at member-function scope at this depth

template<typename if_, int assert_ = if_::assert> struct
 type_assert {};

template<bool> struct
 assertion :
  boost::mpl::true_
    { enum { assert }; };
template<> struct
 assertion<false> :
  boost::mpl::false_
    {};

template<int depth_> struct
 too_deep_in_class :
  assertion<depth_ <= class_max_depth>
    {};

template<int depth_> struct
 too_deep_in_function :
  assertion<depth_ <= function_max_depth>
    {};

template<int depth_> struct
 depth {
  enum depth_e { result = depth_ };
  // assert at class scope
  BOOST_STATIC_ASSERT(( too_deep_in_class<depth_>::value ));
  BOOST_MPL_ASSERT((    too_deep_in_class<depth_>        ));
  typedef type_assert<  too_deep_in_class<depth_>        > assert;
  };

template<typename next_ = void> struct
 recurse {
  template<int depth_>
   int function(depth<depth_> const&) {
    // assert at member function scope
    BOOST_STATIC_ASSERT(( too_deep_in_function<depth_>::value ));
    BOOST_MPL_ASSERT((    too_deep_in_function<depth_>        ));
    typedef type_assert<  too_deep_in_function<depth_>        > assert;
    // recurse
    return next_().function(depth<depth_ + 1>());
    }
  operator int() const {
    return recurse<next_>().function(depth<1>());
    }
  };
template<> struct
 recurse<void> {
  template<int depth_>
   int function(depth<depth_> const&) {
    // assert at member function scope
    BOOST_STATIC_ASSERT(( too_deep_in_function<depth_>::value ));
    BOOST_MPL_ASSERT((    too_deep_in_function<depth_>        ));
    typedef type_assert<  too_deep_in_function<depth_>        > assert;
    // dont recurse
    return 0;
    }
  operator int() const {
    return recurse<void>().function(depth<1>());
    }
  };
  
namespace {

  //uncomment below to go deeper
  int do_recurse =
    recurse<recurse<recurse<recurse<recurse< //5
    //recurse<recurse<recurse<recurse<recurse< //10
    //recurse<recurse<recurse<recurse<recurse< //15
    //recurse<recurse<recurse<recurse<recurse< //20
    //recurse<recurse<recurse<recurse<recurse< //25
    //> > > > > //25
    //> > > > > //20
    //> > > > > //15
    //> > > > > //10
    > > > > >(); //5
    
  }
} //namespace tests
#endif //TESTS_RECURSE_HPP