Вопрос

I'm wanting to incorporate a luabind into one of my projects. To do so I need to provide a function which behaves similar to call_function (see below). This function uses some template magic (courtesy of Boost) that I'd appreciate some help with. This is the first time I've really come across template metaprogramming (is that what it's called?) and so I'm a little lost. Here's a few snippets I'd appreciate help with.

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

I'm not really sure what this preprocessor bit is up to, I don't even know what it's called so searching is a little difficult. A is a template type. If I remember correctly #a would insert the literal text of a, but what do the multiple # do? After this preprocessor stuff comes this.

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

    }

As you can see it makes heavy use of Boost. I've googled BOOST_PP_ITERATION but still can't really make out what it's doing. Could someone please explain to me, preferably in the context of this code, what the BOOST_PP stuff is doing, and how it manages to get the arguments into args.

My end goal is to define a call_function within my own code that will generate args which I can pass to an overload of call_function which I'll define. This means I can use the same calling convention, but can also apply some preprocessing before invoking luabind.

This question is quite specific in the way I've worded it, but I hope the concepts are general enough for it to be OK on here.

Это было полезно?

Решение

BOOST_PP_* ist not related to template metaprogramming, its a preprocessor library. Like the name says, it's working with preprocessor magic, doing some really braintwisting things to generate a bunch of similar templates. In your case, that would be the following:

//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);
}

and so on, up to some maximum defined elsewhere (e.g. A0, A1, A2, A3... A9 if the maximum is 10)

The ## is a token concatenation for the preprocessor, in this case concatenation A (or a) with whatever value n has (=> A0, A1, A2, ...). The whole code is in some preprocessing loop.

  • BOOST_PP_ITERATION() gives the current loop index (0, 1, 2...)
  • BOOST_PP_COMMA_IF(X) gives a comma, if the argument is not 0, e.g. the comma before "class A0" in iteration 1 in the template parameter list
  • BOOST_PP_ENUM(n,B,C) gives a comma separated list of B(?, N, C), where N runs from 0..(n-1), i.e. the macro B gets executed n times, so calling BOOST_PP_ENUM(3, LUABIND_TUPLE_PARAMS, _) gives const A0 *, const A1 *, const A2 *
  • BOOST_PP_ENUM_PARAMS(n, X) gives a comma separated list of X##n, e.g. &a0, &a1, &a2 for BOOST_PP_ENUM_PARAMS(3, &a)

Many of the use cases for that Preprocessor magic can be done with variadic templates these days, so if you are lucky you will not come across that stuff again ;) It's not easy to grasp at first sight, because preprocessing does not work like other known C++ features and has some limitations that one has to work around, making it even less easy to understand.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top