Я хочу включить 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
,
Этот вопрос довольно специфичен в том виде, в котором я его сформулировал, но я надеюсь, что концепции достаточно общие, чтобы все было в порядке.
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 ++ имеет некоторые ограничения, которые нужно обойти, что делает его еще менее простым для понимания.
Других решений пока нет …