Reputation: 14827
I wrote some code to generate a boost::mpl::vector
to use as a lookup table for a factorial function, as a test for a more general library function with which a developer may be able to generate a lookup table in the form of a static array of primitives. The function (which would most probably be implemented as a preprocessor macro definition) would accept the name and size of the array to be initialized, as well the name of a class template to be used as the metafunction to initialize each element i of the array.
I thought that the best way to go about doing this without the use of external scripts would be to
boost::mpl::vector
, as is done in the code listing below, and push the return value of the user-supplied metafunction for each element of the array to the back of the vector;__VARARGS__
macro to accomplish this).I know neither how I would accomplish (2) nor whether the procedure I describe is a good way of doing what I seek. Here are the following questions for which I would like answers:
Is my procedure a good way of accomplishing what I seek? If not, please describe a better procedure which would accomplish the same thing, without the use of external scripts.
If my procedure is indeed a good way of accomplishing what I seek, how would I implement (2)?
I will be sure to post a link to the source file containing library function which I describe once I implement it. The code listing follows below.
namespace mpl = boost::mpl;
template <typename x>
struct factorial:
mpl::if_<mpl::greater<x, mpl::int_<1>>,
mpl::multiplies<x, factorial<x::prior>>,
mpl::int_<1>
>::type
{};
template <typename sequence, typename size>
struct compileTable:
mpl::if_<mpl::greater<size, mpl::int_<0>>,
compileTable<
mpl::push_front<sequence, factorial<size>>::type,
size::prior
>,
sequence
>::type
{};
static const int TABLE_SIZE = 13;
typedef compileTable<
mpl::vector<>,
mpl::int_<TABLE_SIZE>
>::type factorialTable;
/*
** This is where I am stuck; how would I use the elements
** of factorialTable to initialize a static array?
*/
Upvotes: 5
Views: 1195
Reputation: 14827
Here is the source code for the file containing the library function, as promised; please be sure to read the remarks I have made below the code listings. Thanks again to aaa for his help in showing me how to initialize a static array using BOOST_PP_ENUM!
Source code for xi/mpl/lut.h:
#ifndef __XI_LUT_INCLUDED__
#define __XI_LUT_INCLUDED__
#ifndef __cplusplus
#error The file __FILE__ requires a C++ compiler in order to be successfully compiled.
#endif
#include <boost/mpl/apply.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#define __XI_LUT_SET_INDEX(z, n, sequence) \
mpl::at_c<sequence, n>::type::value
#define __XI_GENERATE_LUT_IMPL(function, tableType, tableName, tableSize) \
\
template <typename sequence, typename size> \
struct __compileTable_##function##_##tableSize##: \
mpl::if_<mpl::greater<size, mpl::int_<0>>, \
__compileTable_##function##_##tableSize##< \
mpl::push_front<sequence, \
mpl::apply< \
function##<mpl::_>, \
size \
>::type>::type, \
size::prior \
>, \
sequence \
>::type \
{}; \
\
typedef __compileTable_##function##_##tableSize##< \
mpl::vector<>, \
mpl::int_<##tableSize##> \
>::type __compiledTable_##function##_##tableSize##; \
\
static const tableType tableName##[] = { \
BOOST_PP_ENUM( \
tableSize##, \
__XI_LUT_SET_INDEX, \
__compiledTable_##function##_##tableSize## \
) \
}
#define XI_GENERATE_LUT(function, tableType, tableName, tableSize) \
__XI_GENERATE_LUT_IMPL(function, tableType, tableName, tableSize)
#endif
Source code for a useful test file:
#include <boost/mpl/greater.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/placeholders.hpp>
#include <cstdio>
#include <xi/mpl/lut.hpp>
namespace mpl = boost::mpl;
template <typename x>
struct factorial:
mpl::if_<mpl::greater<x, mpl::int_<1>>,
mpl::multiplies<x, factorial<x::prior>>,
mpl::int_<1>
>::type
{};
XI_GENERATE_LUT(factorial, int, FACTORIAL_TABLE, 4);
int main(int argc, char ** argv) {
// This should print '24:'
printf("Result: %d.\n", FACTORIAL_TABLE[3]);
return 0;
}
I will refrain from providing a URL to the file for now so that I can continue to edit the code listing. I am confident that the code can be improved for purposes of compatibility, so it is definitely not in a final state. Here are some known issues:
__COUNTER__
to alleviate this problem since it is a nonstandard macro definition.I have not tried compiling this code on any other compilers except ICC and MSCV, and would like to know how GCC handles it - please let me know of any issues which arise so that proper recourse may be taken. I will post a URL to the file once the code works with little trouble on most major compilers. Any feedback would be greatly appreciated!
Upvotes: 1
Reputation: 51465
http://www.boost.org/doc/libs/1_46_0/libs/preprocessor/doc/index.html
#define MACRO(z, i, data) \
mpl::at_c<data,i>::value
static const data[] = { BOOST_PP_ENUM(N, MACRO, factorialTable) };
Upvotes: 9