11

I'm writing a generalized function wrapper, that can wrap any function into a lua-style call, which has the form

int lua_function( lua_State *L)

And I wish the wrapper function is generated on-the-fly, so I'm thinking of passing the function as a template argument. This is trivial if you know the number (e.g, 2) of arguments:

template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper

However, I don't know the number, so I beg for variadic template argument for help

// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper

The above won't compile, since variadic argument has to be the last one. So I use two level template, the outer template captures types, the inner template captures the function:

template <typename R, typename... Args>
struct func_type<R(Args...)>
{
  // Inner function wrapper take the function pointer as a template argument
  template <R F(Args...)>
  struct func
  {
    static int call( lua_State *L )
    {
      // extract arguments from L
      F(/*arguments*/);
      return 1;
    }
  };
};

That works, except that to wrap a function like

double sin(double d) {}

the user has to write

func_type<decltype(sin)>::func<sin>::apply

which is tedious. The question is: is there any better, user-friendlier way to do it? (I can't use a function template to wrap the whole thing, coz a function parameter can't be used as a template argument.)

Constantinius
  • 34,183
  • 8
  • 77
  • 85
Ralph Zhang
  • 5,015
  • 5
  • 30
  • 40
  • I think function pointer can be a template argument. It works at least for MSVC. Similar problem as yours is being solved here: http://stackoverflow.com/questions/4387971/c-passing-method-pointer-as-template-argument . – Juraj Blaho May 16 '11 at 11:49

2 Answers2

9

Things like std::function and std::result_of use the following technique to do what you want regarding variadic templates:

template<typename Signature>
struct wrapper; // no base template

template<typename Ret, typename... Args>
struct wrapper<Ret(Args...)> {
    // instantiated for any function type
};

You could expand the above to add a non-type Ret(&P)(Args...) template parameter (pointers to function work just as well) but you'd still need a decltype at the user level, i.e. wrapper<decltype(sin), sin>::apply. Arguably it would be a legitimate use of the preprocessor if you decide to use a macro to remove the repetition.

template<typename Sig, Sig& S>
struct wrapper;

template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
    int
    static apply(lua_State*)
    {
        // pop arguments
        // Ret result = P(args...);
        // push result & return
        return 1;
    }
};

// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.

The above compiles with gcc-4.5 at ideone. Good luck with implementing the apply that (variadically) pops the arguments (leave me a comment if you open a question about that). Have you considered using Luabind?

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Thanks Luc, I think that's pretty much we can get without macro. Btw, for my purpose (wrapping simple c++ functions), writing an "apply" is easy, I just write a bunch of template specialization called extract_arg<> and do this statci apply(lua_State *L) { P(extract_arg(L)...); } – Ralph Zhang May 18 '11 at 00:55
0

As @Juraj says in his comment, the function pointer can be a template argument, see the following simple example:

#include <iostream>
#include <boost/typeof/typeof.hpp>

void f(int b, double c, std::string const& g)
{
  std::cout << "f(): " << g << std::endl;
}

template <typename F, F* addr>
struct wrapper
{
  void operator()()
  {
    std::string bar("bar");
    (*addr)(1, 10., bar);
  }  
};

int main(void)
{
  wrapper<BOOST_TYPEOF(f), &f> w;
  w();
  return 0;
}

working version: http://www.ideone.com/LP0TO

I'm using BOOST_TYPEOF as normally I always provide examples in the current standard, but it does something similar to decltype. Is this what you were after?

Nim
  • 33,299
  • 2
  • 62
  • 101