Преобразование вектора MPL в статический массив

Я написал некоторый код для создания boost::mpl::vector для использования в качестве таблицы поиска для факториальной функции, в качестве теста для более общей библиотечной функции, с помощью которой разработчик может создать таблицу поиска в виде статического массива примитивов. Функция (которая, скорее всего, будет реализована как определение макроса препроцессора) примет имя и размер инициализируемого массива, а также имя шаблона класса, который будет использоваться в качестве метафункции для инициализации каждого элемента i массива.

Я подумал, что лучший способ сделать это без использования внешних скриптов — это

  1. Создайте boost::mpl::vector, как это сделано в листинге кода ниже, и поместите возвращаемое значение введенной пользователем метафункции для каждого элемента массива в конец вектора;
  2. Используйте элементы вектора для инициализации статического массива (возможно, с помощью ряда макросов, последний из которых будет использовать макрос __VARARGS__ для достижения этой цели).

Я не знаю ни того, как бы я выполнил (2), ни того, является ли описываемая процедура хорошим способом сделать то, что я ищу. Вот следующие вопросы, на которые я хотел бы получить ответы:

  1. Является ли моя процедура хорошим способом достижения того, что я ищу? Если нет, опишите лучшую процедуру, которая сделает то же самое без использования внешних скриптов.

  2. Если моя процедура действительно является хорошим способом достижения того, что я ищу, как бы я реализовал (2)?

    Я обязательно опубликую ссылку на исходный файл, содержащий библиотечную функцию, которую я опишу, как только реализую ее. Список кодов следует ниже.

    пространство имен 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?
    */
    

person void-pointer    schedule 25.02.2011    source источник
comment
используйте boost.org/doc/libs /1_45_0/libs/mpl/doc/refmanual/for-each.html   -  person Anycorn    schedule 25.02.2011
comment
Я немного запутался здесь - поскольку for-each - это алгоритм времени выполнения, как бы я использовал его для инициализации статического массива?   -  person void-pointer    schedule 25.02.2011
comment
что именно вы подразумеваете под статическим массивом? static int foo[]?   -  person Anycorn    schedule 25.02.2011
comment
Извините, чтобы уточнить, я имею в виду статический массив констант, который инициализируется во время компиляции, например static int * const FOO = { ... }   -  person void-pointer    schedule 25.02.2011


Ответы (2)


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) };
person Anycorn    schedule 25.02.2011

Вот исходный код файла, содержащего библиотечную функцию, как и было обещано; обязательно прочитайте комментарии, которые я сделал под листингом кодов. Еще раз спасибо aaa за помощь в демонстрации того, как инициализировать статический массив с помощью BOOST_PP_ENUM!

Исходный код для 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

Исходный код полезного тестового файла:

#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;

}

Я пока воздержусь от предоставления URL-адреса файла, чтобы продолжить редактирование листинга кода. Я уверен, что код можно улучшить в целях совместимости, поэтому он точно не в финальном состоянии. Вот некоторые известные проблемы:

  1. Код не будет компилироваться в MSVC 9.0.
  2. Попытка создать таблицу поиска определенного размера для имени метафункции после того, как таблица такого же размера и для того же имени метафункции уже создана, приведет к ошибке, поскольку для этих параметров будут определены соответствующие типы и шаблоны. Я не хочу использовать __COUNTER__ для решения этой проблемы, так как это нестандартное определение макроса.

Я не пробовал компилировать этот код на каких-либо других компиляторах, кроме ICC и MSCV, и хотел бы знать, как с этим справляется GCC. Пожалуйста, сообщайте мне о любых возникающих проблемах, чтобы можно было принять соответствующие меры. Я опубликую URL-адрес файла, как только код будет работать с небольшими проблемами на большинстве основных компиляторов. Любая обратная связь будет принята с благодарностью!

person void-pointer    schedule 25.02.2011