#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