BOOST_PP_ITERATION用于可变长度参数

时间:2013-01-11 06:54:44

标签: c++ templates boost template-meta-programming boost-preprocessor

我想将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之前应用一些预处理。

这个问题在我说的方式上非常具体,但我希望这些概念足够通用,可以在这里使用。

1 个答案:

答案 0 :(得分:3)

BOOST_PP_ *与模板元编程无关,它是一个预处理器库。就像这个名字所说的那样,它正在使用预处理器魔术,做一些真正的braintwisting事情来生成一堆类似的模板。在您的情况下,这将是以下内容:

//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具有的任何值(=&gt; A0,A1,A2,...)。整个代码处于一些预处理循环中。

  • BOOST_PP_ITERATION()给出当前循环索引(0,1,2 ......)
  • BOOST_PP_COMMA_IF(X)给出逗号,如果参数不为0,例如模板参数列表
  • 中迭代1中“类A0”之前的逗号
  • 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 ++特性一样,它有一些必须解决的局限性,使其更难以理解。