BOOST_PP_ITERATION для аргументов переменной длины

Я хочу включить luabind в один из моих проектов. Для этого мне нужно предоставить функцию, которая ведет себя подобно call_function (увидеть ниже). Эта функция использует некоторую магию шаблона (любезно предоставленную Boost), с которой я был бы признателен за помощь. Это первый раз, когда я действительно сталкиваюсь с метапрограммированием шаблонов (так оно называется?), И поэтому я немного растерялся. Вот несколько фрагментов, с которыми я бы хотел помочь.

#define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
#define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n

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

template<class Ret BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
typename boost::mpl::if_<boost::is_void<Ret>
, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
call_function(lua_State* L, const char* name BOOST_PP_COMMA_IF(BOOST_PP_ITERATION()) BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _) )
{
typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
#if BOOST_PP_ITERATION() == 0
tuple_t args;
#else
tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
#endif

}

Как вы можете видеть, он активно использует Boost. Я гуглил BOOST_PP_ITERATION но до сих пор не могу разобрать, что он делает. Может ли кто-нибудь объяснить мне, желательно в контексте этого кода, что BOOST_PP как дела, и как ему удается получить аргументы в args,

Моя конечная цель — определить call_function в моем собственном коде, который будет генерировать args который я могу передать перегрузке call_function который я определю. Это означает, что я могу использовать то же соглашение о вызовах, но также могу применить некоторую предварительную обработку перед вызовом luabind,

Этот вопрос довольно специфичен в том виде, в котором я его сформулировал, но я надеюсь, что концепции достаточно общие, чтобы все было в порядке.

3

Решение

BOOST_PP_ * не связан с метапрограммированием шаблонов, это библиотека препроцессора. Как следует из названия, он работает с магией препроцессора, выполняя некоторые действительно сложные действия для создания множества похожих шаблонов. В вашем случае это будет следующим:

//preprocessor iteration 0
template<class Ret>
typename boost::mpl::if_<boost::is_void<Ret>
, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<> >
, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<> > >::type
call_function(lua_State* L, const char* name )
{
typedef boost::tuples::tuple<> tuple_t;
tuple_t args;
}

//preprocessor iteration 1
template<class Ret , class A0>
typename boost::mpl::if_<boost::is_void<Ret>
, luabind::detail::proxy_function_void_caller<boost::tuples::tuple<const A0 *> >
, luabind::detail::proxy_function_caller<Ret, boost::tuples::tuple<const A0 *> > >::type
call_function(lua_State* L, const char* name , const A0 & a0 )
{
typedef boost::tuples::tuple<const A0 *> tuple_t;
tuple_t args(&a0);
}

и так далее, вплоть до некоторого максимума, определенного в другом месте (например, A0, A1, A2, A3... A9 если максимум 10)

## это конкатенация токенов для препроцессора, в данном случае конкатенация A (или a) с любым значением n (=> A0, A1, A2, …). Весь код находится в некотором цикле предварительной обработки.

  • BOOST_PP_ITERATION() дает текущий индекс цикла (0, 1, 2 …)
  • BOOST_PP_COMMA_IF(X) дает запятую, если аргумент не равен 0, например запятая перед «классом A0» в итерации 1 в списке параметров шаблона
  • BOOST_PP_ENUM(n,B,C) дает разделенный запятыми список B (?, N, C), где N начинается с 0 .. (n-1), то есть макрос B выполняется n раз, поэтому вызов BOOST_PP_ENUM (3, LUABIND_TUPLE_PARAMS, _) дает const A0 *, const A1 *, const A2 *
  • BOOST_PP_ENUM_PARAMS(n, X) дает разделенный запятыми список X ## n, например, &a0, &a1, &a2 за BOOST_PP_ENUM_PARAMS(3, &a)

В наши дни многие варианты использования этой магии препроцессора могут быть выполнены с помощью шаблонов с переменными числами, поэтому, если вам повезет, вы больше не столкнетесь с подобными вещами;) Это не легко понять с первого взгляда, потому что предварительная обработка не работает, как другие известные C ++ имеет некоторые ограничения, которые нужно обойти, что делает его еще менее простым для понимания.

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector