简体   繁体   中英

metaprogramming, factorial, C++, boost

Need to cacl factorial of all numbers from 1 to k and save them in mpl container using boost/mpl.

Range of this nums storaged in range_c. The difficulty is that I have to storage all previous values: k! = (k-1)!*k k! = (k-1)!*k

I thought that I will storage previous values in mpl::vector_c, ie each iteration I will take value from source range_c and multiplie it with previous value (k-1)! which contains in vector_c, but I have a lot of mistakes in this code:

namespace mpl = boost::mpl;
const int border = 10;
using namespace mpl;

typedef
    range_c <int, 1, border>
Numbers;

typedef vector_c<int, 1> data;

typedef
   mpl::transform
  <
    Numbers,
    data,
    push_back<data, multiplies <_, _>>,
    back_inserter
    <
      mpl::vector <>
    >
  >::type
    Factorials;

In all implementations factorial was calculated for each number from 1. In the task i need to calc each next factorial by multiplication with previous factorial. Here right code:

namespace mpl = boost::mpl;
using namespace mpl;
const int border = 15;

typedef range_c<int, 1, border> nums;
typedef vector<int_<1>> data;

typedef mpl::fold<
    nums, data,
    mpl::push_back<_1, mpl::multiplies<_2, back<_1>>>
>::type Factorials;

You may use the following:

namespace detail
{
    // General computation of factorial
    template <std::size_t N>
    struct factorial :
        std::integral_constant<std::size_t, N * factorial<N - 1>::value>
    {
    };

    // special case for 0
    template <>
    struct factorial<0> : std::integral_constant<std::size_t, 1u>
    {};

    // helper to create the sequence of factorial value
    template <typename T> struct factorial_seq_impl;

    template <std::size_t...Is>
    struct factorial_seq_impl<std::index_sequence<Is...>>{
        using type = std::index_sequence<factorial<Is>::value...>;
    };

}

// And finally
template <std::size_t N>
using factorial_seq =
    typename detail::factorial_seq_impl<std::make_index_sequence<N>>::type;

static_assert(std::is_same<std::index_sequence<1, 1, 2, 6, 24>, factorial_seq<5>>::value, "");

Live Demo .

A factorial mpl version and a collection of first 10 results in a vector:

template <typename current, typename to, typename result>
struct calc :
    eval_if< less_equal< current, to >,
    calc< typename current::next, to, typename multiplies< result, current > >,
    result
    >::type
{};

template<typename value>
struct factorial :
    calc<int_<1>, value, int_<1> >::type
{};

template <>
struct factorial<int_<0> > :
    int_<1>::type
{};

template <>
struct factorial<int_<1> > :
    int_<1>::type
{};

template <int value>
struct factorial_c :
    factorial<int_<value> >::type
{};

struct factorial_collection_10 :
    transform<
    range_c<int, 0, 10>,
    factorial<boost::mpl::_1>,
    back_inserter<vector0<> >
    >::type
{};

Test code:

int main()
{
    // get 5! value
    std::cout << "5! = " << factorial_c<5>::value << std::endl;

    // access 6th element of the factorial collection
    std::cout << "6! = " << at<factorial_collection_10, int_<6> >::type::value << std::endl;

    // copy factorial collection to std vector to check values at runtime
    std::vector<int> factorialVec;
    for_each< factorial_collection_10, boost::mpl::_1 >(boost::bind(static_cast<void(std::vector<int>::*)(const int&)>(&std::vector<int>::push_back), &factorialVec, boost::lambda::_1));

    std::cout << "First 10 factorial numbers: " << std::endl;
    for (std::size_t x = 0; x < factorialVec.size(); ++x)
        std::cout << x << "! = " << factorialVec[x] << std::endl;

    return 0;
}

Output:

5! = 120
6! = 720
First 10 factorial numbers:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM