#include <boost/mpl/assert.hpp> | |
#include <boost/mpl/at.hpp> | |
#include <boost/mpl/back_inserter.hpp> | |
#include <boost/mpl/copy.hpp> | |
#include <boost/mpl/divides.hpp> | |
#include <boost/mpl/empty_sequence.hpp> | |
#include <boost/mpl/equal.hpp> | |
#include <boost/mpl/equal_to.hpp> | |
#include <boost/mpl/fold.hpp> | |
#include <boost/mpl/for_each.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/mpl/joint_view.hpp> | |
#include <boost/mpl/less.hpp> | |
#include <boost/mpl/minus.hpp> | |
#include <boost/mpl/modulus.hpp> | |
#include <boost/mpl/push_back.hpp> | |
#include <boost/mpl/range_c.hpp> | |
#include <boost/mpl/string.hpp> | |
#include <boost/mpl/transform.hpp> | |
#include <boost/mpl/vector.hpp> | |
#include <iostream> | |
using namespace boost::mpl; | |
template <typename n> | |
struct NumberInEnglish | |
{ | |
// Can't handle >= 100 | |
BOOST_MPL_ASSERT(( less<n, int_<100> > )); | |
typedef int_<10> ten; | |
typedef int_<20> twenty; | |
typedef char_<'-'> dash; | |
typedef vector< | |
string<>, // use Ones vector | |
string<>, // use Teens vector | |
string<'twen','ty'>, | |
string<'thir','ty'>, | |
string<'four','ty'>, | |
string<'fift','y'>, | |
string<'sixt','y'>, | |
string<'seve','nty'>, | |
string<'eigh','ty'>, | |
string<'nine','ty'> > Tens; | |
typedef vector< | |
string<'no ','more'>, | |
string<'one'>, | |
string<'two'>, | |
string<'thre','e'>, | |
string<'four'>, | |
string<'five'>, | |
string<'six'>, | |
string<'seve','n'>, | |
string<'eigh','t'>, | |
string<'nine'> | |
> Ones; | |
typedef vector< | |
string<'ten'>, | |
string<'elev','en'>, | |
string<'twel','ve'>, | |
string<'thir','teen'>, | |
string<'four','teen'>, | |
string<'fift','een'>, | |
string<'sixt','een'>, | |
string<'seve','ntee','n'>, | |
string<'eigh','teen'>, | |
string<'nine','teen'> | |
> Teens; | |
typedef if_< | |
modulus<n, ten>, | |
typename copy< | |
joint_view< | |
typename push_back<typename at<Tens, divides<n, ten> >::type, dash>::type, | |
typename at<Ones, modulus<n, ten> >::type>, | |
back_inserter<string<> > | |
>::type, | |
typename at<Tens, divides<n, ten> >::type | |
> DoubleDigit; | |
typedef typename if_< | |
less<n, ten>, | |
typename at<Ones, n>::type, | |
typename if_< | |
less<n, twenty>, | |
typename at<Teens, minus<n, ten> >::type, | |
typename DoubleDigit::type | |
>::type | |
>::type type; | |
}; | |
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<4> >::type, string<'four'> > )); | |
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<14> >::type, string<'four','teen'> > )); | |
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<20> >::type, string<'twen','ty'> > )); | |
BOOST_MPL_ASSERT(( equal< NumberInEnglish<int_<44> >::type, string<'four','ty-f','our'> > )); | |
template <typename n> | |
struct CountBottles | |
{ | |
typedef string<'bott','le'> Bottle; | |
typedef typename copy< | |
joint_view< | |
typename push_back< | |
typename NumberInEnglish<n>::type, char_<' '> >::type, | |
typename if_< | |
equal_to<n, int_<1> >, | |
Bottle, | |
push_back<Bottle, char_<'s'> >::type | |
>::type | |
>, | |
back_inserter<string<> > | |
>::type type; | |
}; | |
BOOST_MPL_ASSERT(( equal< CountBottles<int_<0> >::type, string<'no m','ore ','bott','les'> > )); | |
BOOST_MPL_ASSERT(( equal< CountBottles<int_<1> >::type, string<'one ','bott','le'> > )); | |
BOOST_MPL_ASSERT(( equal< CountBottles<int_<14> >::type, string<'four','teen',' bot','tles'> > )); | |
template <typename n> | |
struct Verse | |
{ | |
typedef string<'\n'> NL; | |
typedef string<',\n'> CommaNL; | |
typedef string<' of ','beer'> OfBeer; | |
typedef string<' on ','the ','wall'> OnTheWall; | |
typedef string<'take',' one',' dow','n, p','ass ','it a','roun','d,\n'> TakeOneDownPassItAround; | |
typedef typename transform< | |
vector< | |
typename CountBottles<n>::type, | |
OfBeer, | |
OnTheWall, | |
CommaNL, | |
typename CountBottles<n>::type, | |
OfBeer, | |
CommaNL, | |
TakeOneDownPassItAround, | |
typename CountBottles<typename prior<n>::type>::type, | |
OfBeer, | |
NL, | |
NL | |
>, | |
c_str<_1> | |
>::type strings; | |
}; | |
struct PrintValue | |
{ | |
PrintValue(std::ostream& os) : os_(os) {} | |
std::ostream& os_; | |
template <typename T> | |
void operator() (T t) | |
{ | |
os_ << T::value; | |
} | |
}; | |
template <typename n> | |
std::ostream& operator<< (std::ostream& os, Verse<n> verse) | |
{ | |
boost::mpl::for_each<typename Verse<n>::strings>(PrintValue(os)); | |
}; | |
struct PrintTo | |
{ | |
PrintTo(std::ostream& os) : os_(os) {} | |
std::ostream& os_; | |
template <typename T> | |
void operator() (T t) | |
{ | |
os_ << t; | |
} | |
}; | |
int main() | |
{ | |
boost::mpl::for_each< | |
range_c<int, 1, 100>, | |
lambda< | |
Verse<minus<int_<100>, _1> > | |
>::type>( | |
PrintTo(std::cout)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment